Get all items from adapter (recyclerview) in Fragment - android

Hello I'm having an issue getting all of the items from my adapter in my fragment. To be more specific I am using a ScaleInAnimatorAdapter along with my Customer Adapter and when I attempt to get my checkbox items from the below posted code, within my Fragment, I only seem to get the visible items on screen.
private View.OnClickListener onAllClick = new View.OnClickListener() {
#Override public void onClick(View v) {
int count = listAdapter.getItemCount();
for (int i = 0; i < count; i++) {
View mChild = listTopics.getChildAt(i);
if( mChild != null ) {
Log.d(TAG,"getItemCount(): " + i );
CheckBox cBox = (CheckBox)mChild.findViewById(R.id.topic_chk);
cBox.setChecked(((CheckBox) v).isChecked());
Log.d(TAG,"isChecked" + cBox.getTag());
cBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(((CheckBox) v).isChecked()) {
checkboxAll.setChecked(false);
}
}
});
}
}
}
};
Essentially I am attempting to create a check all feature from the fragment, so that when this is clicked all of the checkbox items from the adapter are checked. I got that to work with the code I presented however the main issue is that I only get the items visible on the screen, so when I scroll to my other items they are not checked. Thus I am wondering if there is a better way or another way for me to get all of the items

Adapters are meant to bind underlying data stores to views; they generally shouldn't be used to store data themselves (except for having a copy of the data for view binding purposes) nor should they perform actions on data.
Instead, you should be modifying the underlying data, then updating the adapter through whatever mechanism you are already using. (Loaders, custom setters with notifyDataItemChanged, etc.).

Basically you can't. It'll be reusing the UI views.
You need to set a flag in all your data list objects, call notifyDataSetChanged() and onBindViewHolder check that flag and use it to check uncheck
if(listAdapter.getItem(position).getIsChecked())
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);

Ok. Thank you all for those who have replied you helped me grasp something really basic and important that had alluded me.
I got it to work, so for anyone who might read this post, here is my solution:
Create necessary methods and field to update your data in a model (ie, private is_checked, set_checked(), is_checked(), etc)
In your adapter onBindViewHolder, you will set your holder checkbox to be associated to the data so something like:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
obj.setSelected(buttonView.isChecked());
}
});
holder.checkBox.setChecked(obj.isSelected());
Then in your fragment or activity I just have a click listener on my main checkbox, and then when checked I loop through my data list, and using the model method I update my data and just simply use listAdapter.notifyDataSetChanged()

You are doing it wrongly.
You should update the adapter instead of updating the check box view.
What you can do , you can create a field in adapter data holder .
And whenever you change the selection,just update the field or multiple field and finally refresh the view.

Related

Select multiple items from recycler view list delete not working Properly

if (RFidList.size() >0){
for (String s: RFidList){
RFidTagValueList.remove(s);
}
}
mTimeAdapter.notifyDataSetChanged();
dialog.dismiss();
when choose multiple items in recyclerview checkbox not working / and am use private ArrayList<String> data = new ArrayList<>();
You can't move and delete from the list. The best option to do this is to have an array that will remember the state of the checkbox. Scrolling through your recycler view will always change the state of the checkbox and maybe won't remember it. The way to do this is to add an array of boolean
private boolean[] checkStates;
then inside your constructor of the adapter do this.
checkStates = new boolean[data.size()];
This way you'll create an array of boolean filled with FALSE value the same size your data array is. Now, inside your adapter when you are binding your view do this for the checkbox.
holder.checkbox.setChecked(checkStates[position]);
Also, don't use onCheckedChangeListener on checkbox inside adapter. This will be called even when you scroll and it will change whatever you are doing inside the function. What you can do is override onClick for the checkbox, but there is something tricky here. When you click the checkbox to check it, inside the onClick method the view will have the state as it is already checked so to follow this do it like this:
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Checkbox c = (CheckBox) v;
checkStates[position] = c.isChecked();
}
});
I wrote this from my head and maybe there are some mistakes but you'll get the point. The animation of the check state will be handled you just need to handle changes inside the checkStates array.
Now your checkbox will always have the state it had before. After this, you can create a function to delete items from your data.
public void removeItems() {
ArrayList<YOUR-MODEL> items_to_delete = new ArrayList<>();
for (int i = 0; i < checkStates.length(); ++i) {
if (checkStates[i]) items_to_delete.add(data.get(i]);
}
data.removeAll(items_to_delete);
notifyDataSetChanged();
checkStates = new boolean[data.size()];
}
This works if your data is a type of ArrayList. I think this is the best way to go.

Strange RecyclerView Checkbox onCheckChanged Behavior

I am working where I have checkboxe inside RecyclerView items. I am aware of some of its issues. But, with only 10 items and no scrolling wrong listener is called.
I have something like this:
private class MyAdapter extends RecyclerView.Adapter<MyViewHodler> {
ArrayList<String> items;
ArrayList<String> checkedList = new ArrayList<>();
...
public void onBindViewHolder(final MyViewHolder holder, int position) {
String item = items.get(position);
String check = checkedList.get(item);
if(check != null)
holder.vChecked.setChecked(true);
else
holder.vChecked.setChecked(false);
....
holder.vChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked) {
checkedList.add(item);
} else {
checkedList.remove(item);
}
}
}
}
Now, strangely this checkedChange calls are made on different views. I have a list of only 10 items and are fit in the recyclerview, no scrolling. I externally change the data (items and checked list), set the new data and calling myAdapter.notifyDatasetChanged()
This call removes one more item from the checked state.
For example, I have 10 items all checked. I uncheck 1 item, and doing some other calculations based on that and calling myAdapter.notifyDatasetChanged(). It also unchecks one more element from the other 9 items.
So even without scrolling why onCheckedChange listener is called for the wrong view?
I have found out the problem. I thought onBindViewHolder is called for every view to change the data. But I was wrong.
notifyDatasetChanged() recycles all the view holders on screen and from the recycled view holder pool randomly viewholders are picked to bind the new data. So when I called the notifyDatasetChanged, the viewholder was used at the different position, and thus changed one more item.
So, I removed the listener to null in onViewRecycled method of the recycler view. Like this:
#Override
public void onViewRecycled(MyViewHolder holder) {
super.onViewRecycled(holder);
holder.vChecked.setOnCheckedChangeListener(null);
}
This, did solved the issue. I was aware of this, but I thought viewholders are reused for the same position if there is no scrolling. But onDatasetChanged recycles all currently used view holders and uses it again from the random pool.
This line: String item = items.get(item);
It bothers me. Shouldn't it be String item = items.get(position);
Edit: If you change one position of the dataset, call notifyItemChanged. Don't notify the whole dataset unless it has changed entirely. Could be this.
Edit 2: Well then the problem is not that onCheckedChanged is being called on the wrong views. It is called in all of the views because you always change the checkbox state at onBindViewHolder

How to set textView in a recyclerView at desired position

I have a recyclerView in which i have a list of items displayed in a LinearLayout.There is a "increase" button in every list which will increment a quantity by "1".But when I click the button on the first list item to increment the number..the incremented value is displayed in the last list item of the recyclerView not in the desired position where i clicked.Can anyone help me find the solution?
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
myholder = holder;
holder.item_name_text.setText(data.get(position).getName());
holder.item_price_text.setText(data.get(position).getPrice().toString());
holder.item_quantity_text.setText("500");
//Adding item to the cart
holder.add_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(totalItem>=0 && totalItem<10){
totalItem++;
myholder.item_totalquantity_text.setText(String.valueOf(totalItem));
}else{
Toast.makeText(myholder.itemView.getContext(),"Cannot add more item",Toast.LENGTH_SHORT).show();
}
}
});
So I always think of recyclerviews as the frontend that displays my data. If you would like to make changes to the actual data itself and make sure it gets reflected in the recyclerview, you will need to ensure the changes are made inside the arraylist of data objects.
You will need to add a field inside the data object and call it counter. Then you must increment the counter once the user clicks on the onClickListener.
myholder.item_totalquantity_text.setText(data.get(position).setCounter(data.get(position).getCounter())+1);
Do not set OnClickListener() in onBindViewHolder(). Instead do it in your ViewHolder class itself. And main ly as RecyclerView re-uses the holder objects to represent the new set of data that is becoming visible. So the listener on which yo click might be belonging to some other view holder so it appears there instead.
Have a quick read of this and this. These are not very relevant to you but it has info to understnad recycling concept so you can fix your stuff easily.

onclick checkbox in listview

I have looked other questions but none of them fulfill what I need.
I have a listview showing a list of objects (alarms) that have some textviews and a checkbox. As you can imagine, this checkbox is to activate and deactivate that alarm.
When I arrive to this screen (alarms list), it checks the active state in the database, so some of the checkboxes are checked and some other not.
What I need is to click in the checkbox and change the state in the database for that alarm at the moment. Not checking the state of all checkboxes before leaving the screen!!! I have read solutions using selectedItems or Holder class, but are not suitable for me.
I think I need to define the onClick event in the checkbox (in the AlarmAdapter), but the list of alarms is in the activity (ListAlarms), so I don't know how to "tell" the list of alarms "this is the checkbox (alarm) that has been clicked, then update its active state".
Any idea? Maybe controlling the action in the row (with OnItemClickListener) instead of clicking the checkbox?
Thanks a lot!!!
I think if you read the response here you will have your answer:
How to get selected list items from a Listview with checkBox and Custom Adapter?
Finally, I have done a non-clean solution:
This code in the adapter:
CheckBox active = (CheckBox) view.findViewById(R.id.cb_active);
active.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
a.toggle();
boolean exists = false;
for(Alarm aux : modifiedAlarms){
if(aux.getId() == a.getId()){
exists = true;
}
}
if(!exists){
modifiedAlarms.add(a);
}
else{
//this is to guarantee that the alarm has the same state than the added one.
a.toggle();
modifiedAlarms.remove(a);
a.toggle();
}
}
});
active.setTag(a);
And this code in the activity, when leaving the screen:
ImageView back = (ImageView)findViewById(R.id.iv_back);
back.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<Alarm> modified = adapter.getModifiedAlarms();
for(Alarm a : modified){
dataalarms.activeAlarm(a.getId(), a.getActive());
}
finish();
}
});
If anybody knows how to get the onClick event in the activity, it would be nice to answer here.
Thanks! :)
This is where the custom object comes in. You create an array of these objects, and then you set a flag in the onClick event of your checkbox in the adapter. Then you can access this object and check the flag. Sorry for creating new answers, but my rep isn't high enough to comment.

How to handle events from a CheckedChangedListener in a ListView

Iv'e got a custom Listview implemented in this particular class, it looks like
[Image/Textview/Checkbox]
When someone clicks on the text is should launch another class, this is working at the moment, however when someone clicks a checkbox I want to update an array that stores the current state of all the checkboxes, I tried doing that via using a onCheckedChanged method within the custom adapter however it doesn't work as the position variable isn't final. So two questions
1 within the adapter is their a way to get the position of the Checkbox so I can change the right position in the array, and
2 If not is their another way to update the array somewhere else without disrupting the current functionality of the onClick.
Here is my onCheckedChanged within my adapter
CheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton but, boolean b) {
// TODO Auto-generated method stub
if(but.isChecked())
{
deleteList[???] = true;
}else{
deleteList[???] = false;
}
}
});
Have a look a this method. You can set a tag to a view containing any object you wish, which in your case may be the integer value associated with the CheckBox's row.
So when you create your CheckBox:
but.setTag(new Integer(position));
This would change your if statement to:
if (but.isChecked()){
deleteList[((Integer) but.getTag()).intValue()] = true;
} else {
deleteList[((Integer) but.getTag()).intValue()] = false;
}
Let me know if this helps!

Categories

Resources