How to update SpeedView inside ListView without initial animation? - java

So I have a fragment with three speedview gauges in it. Picture of fragment They used to be in the fragment directly and would work fine, but after I needed to add the textviews, I couldn't get everything to fit on the screen so I decided to create a custom layout and use a list view to display them.
It used to be very easy to update the speedometers and everythign worked fine.
After adding everything to a listview the only way I can think to get everything to update is to use notifyDataSetChanged() on the adapter, but when I do this, the gauge indicator snaps to 0 and goes up to the desired number from there. I have tried using a holder to maybe fix the problem, but no luck.
This is the fragment's code on how I create the adapter
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
OEEsegmentList = (ListView) view.findViewById(R.id.OEEplusLV);
qualitySegment = new OEEListSegment("Quality", OEEqualityValueString, "Bad parts: "+OEEqualityBadPartsValueString, "Total parts: "+OEEqualityTotalPartsValueString);
availabilitySegment = new OEEListSegment("Availability", OEEavailabilityValueString, "Downtime: "+OEEavailabilityDowntimeValueString, "Next time: "+OEEavailabilityNextTimeValueString);
performanceSegment = new OEEListSegment("Performance", OEEperformanceValueString, "Act time: "+OEEperformanceActTimeValueString, "Takt time: "+OEEperformanceTaktTimeValueString);
OEEsegmentArrayList = new ArrayList<>();
OEEsegmentArrayList.add(qualitySegment);
OEEsegmentArrayList.add(availabilitySegment);
OEEsegmentArrayList.add(performanceSegment);
OEEadapter = new OEEListAdapter(getActivity(), R.layout.oee_list_layout, OEEsegmentArrayList);
OEEsegmentList.setAdapter(OEEadapter);
}
and here is one of the update functions, they're all basically the same code with different names. I call them in the main activity when I recieve a message about the particular marker being changed.
public void updateOEEplusAvailability (String availability) {
OEEavailabilityValueString=availability;
availabilitySegment.setSegmentValueDial(OEEavailabilityValueString);
OEEadapter.notifyDataSetChanged();
}
this is my entire list adapter
public class OEEListAdapter extends ArrayAdapter<OEEListSegment> {
private Context mContext;
int mResource;
public ArrayList<OEEListSegment> mSegments ;
public OEEListAdapter(#NonNull Context context, int resource, #NonNull ArrayList<OEEListSegment> objects) {
super(context, resource, objects);
mContext = context;
mResource = resource;
mSegments=objects;
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
holder = new ViewHolder();
String name = getItem(position).getSegmentName();
String valueDial = getItem(position).getSegmentValueDial();
String valueTV1 = getItem(position).getSegmentValueTV1();
String valueTV2 = getItem(position).getSegmentValueTV2();
final OEEListSegment Segment = new OEEListSegment(name, valueDial, valueTV1, valueTV2);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
TextView textViewName = (TextView) convertView.findViewById(R.id.textViewSegmentName);
holder.speedView = (SpeedView) convertView.findViewById(R.id.segmentSpeedView);
holder.textViewFirst = (TextView) convertView.findViewById(R.id.textViewSegmentFirst);
holder.textViewSecond=(TextView) convertView.findViewById(R.id.textViewSegmentSecond);
convertView.setTag(holder);
holder.textViewFirst.setText(mSegments.get(position).getSegmentValueTV1());
holder.textViewSecond.setText(mSegments.get(position).getSegmentValueTV2());
holder.speedView.speedTo(Float.parseFloat(mSegments.get(position).getSegmentValueDial()));
holder.speedView.clearSections();
holder.speedView.addSections(
new Section(.3f, Color.RED)
, new Section(.7f, Color.YELLOW)
, new Section(1f, Color.GREEN));
textViewName.setText(name);
holder.textViewFirst.setText(valueTV1);
holder.textViewSecond.setText(valueTV2);
holder.speedView.speedTo(Float.parseFloat(valueDial));
return convertView;
}
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getCount() {
return mSegments.size();
}
public Object getItemCustom(int position) {
return mSegments.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
private class ViewHolder {
protected SpeedView speedView ;
private TextView textViewFirst ;
private TextView textViewSecond;
}
}
And this is the list segment code
public class OEEListSegment implements Parcelable {
private String name;
private String valueDial;
private String valueTV1;
private String valueTV2;
public OEEListSegment(String name, String valueDial, String valueTV1, String valueTV2) {
this.name=name;
this.valueDial=valueDial;
this.valueTV1=valueTV1;
this.valueTV2=valueTV2;
}
public String getSegmentName() {
return name;
}
public void setSegmentName(String name) {
this.name=name;
}
public String getSegmentValueDial() {
return valueDial;
}
public void setSegmentValueDial(String valueDial) {
this.valueDial=valueDial;
}
public String getSegmentValueTV1() {
return valueTV1;
}
public void setSegmentValueTV1(String valueTV1) {
this.valueTV1=valueTV1;
}
public String getSegmentValueTV2() {
return valueTV2;
}
public void setSegmentValueTV2(String valueTV2) {
this.valueTV2=valueTV2;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {this.name, this.valueDial, this.valueTV1, this.valueTV2});
}
private void readFromParcel(Parcel in) {
name = in.readString();
valueDial= in.readString();
valueTV1= in.readString();
valueTV2= in.readString();
}
public OEEListSegment(Parcel in){
String[] data = new String[4];
in.readStringArray(data);
// the order needs to be the same as in writeToParcel() method
this.name = data[0];
this.valueDial= data[1];
this.valueTV1= data[2];
this.valueTV2= data[3];
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public OEEListSegment createFromParcel(Parcel in) {
return new OEEListSegment(in);
}
public OEEListSegment[] newArray(int size) {
return new OEEListSegment[size];
}
};
}
Any solution would be appreciated. Either how to stop that initial animation (0 to desired number) from happening in the speed view or how to update the listview so that animation doesn't happen.
Or would it be best to omit the list view completely, while still getting this desired layout (there will only ever be 3 segments).

I wasn't able to do what I needed to do inside the list segment, but since I knew the exact number of times I wanted this segment to be shown, I decided to change my approach.
I added a scoll view in my main layout and then included the segment layout 3x inside it. I then needed to access all the components by ID like this to acces the segment (layout)
performanceLayout = view.findViewById(R.id.performanceSegment);
and like this to access the elements inside my segments
speedViewPerformance= performanceLayout.findViewById(R.id.segmentSpeedView);
then I could update the speeviews with funcktions like this
public void updateOEEplusPerformance (String performance) {
OEEperformanceValueString=performance;
speedViewPerformance.speedTo(Float.parseFloat(OEEperformanceValueString));
}
It's much simpler than what I was trying to do before, since I don't need an adapter or a new class, I definitely do not need to change the speedview animation and it works just like I needed it to!

Related

Passing data from Adapter to Item's ViewModel in Android

I have a view pager with an adapter that has a number of items fetched from the cloud. I add the pages to the adapter through the fragment.
I am trying to pass a variable to the Item's view model every time a new page is instantiated from the adapter so as to notify one of the views that depend on this view model. I have tried a few workarounds but nothing has been successful so far. Would anyone please advice how I may pass this data.
Below is my adapter
public class HelpPagerAdapter extends PagerAdapter {
private final List<HelpPage> mHelpPages;
private int currentPage = 0;
public HelpPagerAdapter(Context context) {
mPages = new ArrayList<>();
}
#Override
public int getCount() {
return mHelpPages.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
HelpPage helpPage = mHelpPages.get(position);
currentPage = position;
LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewDataBinding binding = DataBindingUtil.inflate(inflater, helpPage.getLayout(), container, false);
binding.setVariable(helpPage.getViewModelBindingId(), helpPage.getViewModel());
container.addView(binding.getRoot());
return binding.getRoot();
}
public void addPage(#LayoutRes int layout, Object viewModel, int viewModelBindingId) {
mHelpPages.add(new HelpPage(layout, viewModel, viewModelBindingId));
}
private class HelpPage {
private final #LayoutRes int mLayout;
private final Object mViewModel;
private final int mViewModelBindingId;
HelpPage(#LayoutRes int layout, Object viewModel, int viewModelBindingId) {
mLayout = layout;
mViewModel = viewModel;
mViewModelBindingId = viewModelBindingId;
}
#LayoutRes int getLayout() {
return mLayout;
}
Object getViewModel() {
return mViewModel;
}
int getViewModelBindingId() {
return mViewModelBindingId;
}
}
}
Part of my fragment code
#Override
public void onAttach(Context context) {
super.onAttach(context);
Bundle bundle = getArguments();
if (bundle == null || (!bundle.containsKey(ARG_STEPS) && !bundle.containsKey(ARG_VIEWS))) {
throw new IllegalStateException("HelpFragment cannot be initialised without views");
}
HelpPagerAdapter adapter = new HelpPagerAdapter(getContext());
if (bundle.containsKey(ARG_STEPS)) {
List<Step> steps = Parcels.unwrap(bundle.getParcelable(ARG_STEPS));
adapter = addHelpPages(steps, adapter);
}
mHelpViewModel = new HelpViewModel(adapter);
}
private HelpPagerAdapter addHelpPages(List<Step> steps, HelpPagerAdapter adapter) {
for (Step step : steps) {
adapter.addPage(R.layout.layout_help, new HelpItemViewModel(step), BR.viewModel);
}
return adapter;
}
Part of my ViewModel
public class HelpItemViewModel {
private final String mText;
private final String mVideoId;
private final String mImageUrl;
public HelpItemViewModel(Step step) {
mText = step.getText();
mHelpId = step.getHelpId();
mImageUrl = step.getImage();
}
}

show different list items on different catagories activities

Now i want to list items in different categories ex: one of them hospitals and the one item must contain the name, the address and the phone number, I created this if statement in the adapter if the index of has one text invisible others but it didn't work with me well any help code
public class Data {
private String placeWord;
private String addressWord;
private String reason = ONE_TEXT;
private static final String ONE_TEXT = "ah";
public Data(String mPlaceWord , String mAddressWord){
placeWord = mPlaceWord;
addressWord = mAddressWord;
}
public Data(String theReson){
reason = theReson;
}
public String getPlaceWord(){
return placeWord;
}
public String getAddressWord(){
return addressWord;
}
public String getReason(){return reason;}
public boolean oneText(){
return reason != ONE_TEXT;
}
public class DataAdapter extends ArrayAdapter {
private int mColorResourceId;
public DataAdapter(#NonNull Context context, ArrayList<Data> resource ,int ColorResourceId) {
super(context,0, resource);
mColorResourceId = ColorResourceId ;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listitem = convertView;
if( listitem == null){
listitem = LayoutInflater.from(getContext()).inflate(R.layout.list_item,parent,false);
}
Data currentword = (Data) getItem(position);
TextView pd = (TextView) listitem.findViewById(R.id.placetxt);
pd.setText(currentword.getPlaceWord());
TextView ad = (TextView) listitem.findViewById(R.id.adddrestxt);
ad.setText(currentword.getAddressWord());
if (currentword.oneText()){
TextView ps = (TextView) listitem.findViewById(R.id.placetxt);
ps.setText(currentword.getReason());
} else{
pd.setVisibility(View.GONE);
ad.setVisibility(View.GONE);
}
View textContainer = listitem.findViewById(R.id.list_item);
// Find the color that the resource ID maps to
int color = ContextCompat.getColor(getContext(), mColorResourceId);
// Set the background color of the text container View
textContainer.setBackgroundColor(color);
return listitem;
}
}
Use a recycler view and add this logic in its adapter.

RecyclerView index=-1 when scrolling fast to the bottom

I have created a RecyclerView to display items and everything shows and works fine except to one scenario: when I scroll fast to the bottom of the RecyclerView.
If I do so, I get the following error:
java.lang.ArrayIndexOutOfBoundsException: length=15; index=-1
It directs me to this part of my code (specifically to checkIfBorrowed.get( getAdapterPosition() )):
public class itemtestAdapter extends RecyclerView.Adapter<itemtestAdapter.testViewHolder> {
private List<Discoveritems> items;
private List<Boolean> checkIftested;
interface OnItemCheckListener {
void onItemCheck(Discoveritems items);
void onItemUncheck(Discoveritems items);
}
#NonNull
private OnItemCheckListener onItemCheckListener;
public itemtestAdapter(List<Discoveritems> items, List<Boolean> checkIftested, #NonNull OnItemCheckListener onItemCheckListener) {
this.items = items;
this.onItemCheckListener = onItemCheckListener;
this.checkIftested = checkIftested;
}
#Override
public testViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
view = LayoutInflater.from(parent.getContext()).inflate( R.layout.item_item_test_list, parent, false );
return new testViewHolder(view);
}
#Override
public void onBindViewHolder(testViewHolder holder, int position) {
holder.bind(items.get(position));
final Discoveritems currentItem = items.get(position);
holder.setOnClickListener( v -> {
holder.Cb_test.setChecked(
!holder.Cb_test.isChecked());
if (holder.Cb_test.isChecked()) {
onItemCheckListener.onItemCheck(currentItem);
} else {
onItemCheckListener.onItemUncheck(currentItem);
}
} );
}
#Override
public int getItemCount() {
return items.size();
}
class testViewHolder extends RecyclerView.ViewHolder {
ImageView Iv_test,itemPic;
TextView itemName;
CheckBox Cb_test;
Discoveritems items;
public testViewHolder(View itemView) {
super(itemView);
Iv_testitemPic = itemView.findViewById(R.id.iv_itemCover);
Tv_testitemName = itemView.findViewById( R.id.tv_testeditemName);
Cb_test = itemView.findViewById( R.id.cb_testitem );
Cb_test.setClickable( false );
}
public void setOnClickListener(View.OnClickListener onClickListener) {
itemView.setOnClickListener(onClickListener);
}
public void bind(Discoveritems items) {
this.items = items;
String itemID = items.getitemID();
MyitemClient client = new MyitemClient();
client.getitems(itemID, new JsonHttpResponseHandler(){
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response){
if(response!=null){
final Myitem items = Myitem.fromJson(response);
if (checkIftested.get( getAdapterPosition() )){
itemView.setEnabled(false);
Tv_itemName.setText("my" + items.getTitle());
} else {
Tv_itemName.setText( items.getTitle() );
}
}
}
});
}
}
}
Thing is that inside bind I can't figure out how to get the position of the item without using getAdapterPosition and I also cant understand why it only happens when I scroll fast.
Also it is weird that it says length = 15 while checkIfBorowed's size is 12 only.
Thank you
Change holder.bind(items.get(position)); to holder.bind(items.get(position), position); and then change viewholders bind method to accept the new position argument i.e. bind(Discoveritems items, int position) and use position instead of getAdapterPosition().
The issue is you are not using the position the adapter gave your viewholder which can change when views are recycled and thus they dont macth. Please see here for more https://stackoverflow.com/a/38970513/1133011

RecyclerView is duplicating the first three items on a list

Im fairly new to android and i am trying to use a RecyclerView to display content hosted on firebase, but when it comes up the first three items are duplicated.
I have tried a few solutions around but none seem to work, any help would be great!
DiscountRecyclerAdapter.java
public class DiscountRecyclerAdapter extends RecyclerView.Adapter<com.cianod.comharapp.DiscountRecyclerAdapter.ViewHolder> {
public List<Discounts> discountsList;
public Context context;
private ImageView discountImageView;
public DiscountRecyclerAdapter(List<Discounts> discountsList){
this.discountsList = discountsList;
}
#Override
public com.cianod.comharapp.DiscountRecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.discount_list_item, parent, false);
context = parent.getContext();
return new com.cianod.comharapp.DiscountRecyclerAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final com.cianod.comharapp.DiscountRecyclerAdapter.ViewHolder holder, int position) {
holder.setIsRecyclable(false);
String discountName = discountsList.get(position).getDiscount_name();
holder.setDiscount_Name(discountName);
String discountDescription = discountsList.get(position).getDiscount_description();
holder.setDiscount_Description(discountDescription);
String discountValue = discountsList.get(position).getDiscount_value();
holder.setDiscount_Value(discountValue);
String image_url = discountsList.get(position).getDiscount_image();
String thumbUri = discountsList.get(position).getDiscount_image();
holder.setDiscount_Image(image_url, thumbUri);
}
#Override
public int getItemCount() {
if(discountsList != null) {
return discountsList.size();
} else {
return 0;
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
private View mView;
private TextView discount_name;
public ViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDiscount_Name(String message){
discount_name = mView.findViewById(R.id.discount_name);
discount_name.setText(message);
}
public void setDiscount_Description(String message){
discount_name = mView.findViewById(R.id.discount_description);
discount_name.setText(message);
}
public void setDiscount_Value(String message){
discount_name = mView.findViewById(R.id.discount_value);
discount_name.setText(message);
}
public void setDiscount_Image(String downloadUri, String thumbUri){
discountImageView = mView.findViewById(R.id.discount_image);
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.image_placeholder);
Glide.with(context).applyDefaultRequestOptions(requestOptions).load(downloadUri).thumbnail(
Glide.with(context).load(thumbUri)
).into(discountImageView);
}
}
}
I believe the problem is coming from the discount adapter but I cant say for sure. The RecyclerView is displayed on a fragment if that could be influencing it I can attach other pieces if they are necessary.
There is nothing wrong with your code.So maybe you should try to override those two methods in your adapter class
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}

add object to arraylist from another class

I got a problem. I want to add an object named Transactions which is this one:
public class Transaction {
private float value;
private int transaction_date;
private String description;
public Transaction(float value, int transaction_date, String description){
super();
this.value = value;
this.transaction_date = transaction_date;
this.description = description;
}
public float getValue(){
return value;
}
public int getTransaction_date(){
return transaction_date;
}
public String getDescription(){
return description;
}
to an ArrayList in my main activity.
Okay as far not that much of a problem. But how can I do this from another activity where I want to set the required variables (in my case the value, transaction_date and description)?
Here is my Activity where I want to set the values (yes I know that there are no variable inputs yet):
public class AddMoneyTransaction extends AppCompatActivity {
EditText depositInputSix;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_money_transaction);
//transaction list
populateTransactionList();
populateListView();
//setup the button
Button addDepositButton;
addDepositButton = (Button)findViewById(R.id.addDepositButton);
//make it work
addDepositButton.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View view) {
}
});
}
//populated transaction list
protected void populateTransactionList() {
myTransactions.add(new Transaction(1,19,"monday"));
myTransactions.add(new Transaction(2,20,"tuesday"));
myTransactions.add(new Transaction(3,21,"wednesday"));
}
//populated list view
private void populateListView() {
ArrayAdapter<Transaction> adapter = new AssetsOverview.LastTransactionsListAdapter();
ListView list = (ListView) findViewById(R.id.last_transactions_listView);
list.setAdapter(adapter);
}
private class LastTransactionsListAdapter extends ArrayAdapter<Transaction>{
public LastTransactionsListAdapter(){
super(AddMoneyTransaction.this, R.layout.transaction_list_view, myTransactions);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
//make sure there is a view to work with (maybe null)
View itemView = convertView;
if (itemView == null){
itemView = getLayoutInflater().inflate(R.layout.transaction_list_view, parent, false);
}
//find a transaction to work with
Transaction currentTransaction = myTransactions.get(position);
// fill the view:
// value
TextView valueView = (TextView) itemView.findViewById(R.id.transactionValueView);
valueView.setText(currentTransaction.getValue() + "$");
// date
TextView dateView = (TextView) itemView.findViewById(R.id.transactionDateView);
dateView.setText(currentTransaction.getTransaction_date() + "");
// description
TextView descriptionView = (TextView) itemView.findViewById(R.id.transactionDesciptionView);
descriptionView.setText(currentTransaction.getDescription());
return itemView;
}
}
I hope someone can please help me with this since I did not find anything helpful. Please tell me if you need more information...
I assume your myTransactions list is defined inside parent class AppCompatActivity. The problem in
addDepositButton.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View view)
{
}
});
seems to be that myTransactions is not defined as a final variable.
When you create a new anonymous OnClickListener, what the compiler does is it provides to OnClickListener constructor a reference to your myTransactions, if myTransactions is used inside the onClick method. This myTransactions cannot be changed later and must therefore be final.
So for the solution, I would try adding final keyword in the definition of myTransactions.

Categories

Resources