I have a list of checkListItems. List item has a check box. I want to save the status of the item. Status is saved as 0 or 1.
I am showing the check box checked or unchecked based on status 0 or 1.
It shows correct sometimes but when I scroll up and down more items gets checked or unchecked which I have not done manually.
Adapter:
public class CheckListItemAdapter extends RecyclerView.Adapter<CheckListItemAdapter.MyViewHolder>{
private List<CheckListItem> checkListItems;
Context context;
private String status;
private final OnItemClickListener listener;
public interface OnItemClickListener {
void onItemClick(CheckListItem item);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, budget;
public RelativeLayout parent;
private CheckBox checkBox;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
budget =(TextView) view.findViewById(R.id.budget);
checkBox = (CheckBox) view.findViewById(R.id.checkBox);
}
public void bind(final CheckListItem item, final OnItemClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
}
public CheckListItemAdapter(List<CheckListItem> checkListItems,Context context,OnItemClickListener listener) {
this.checkListItems = checkListItems;
this.context = context;
this.listener = listener;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.checklist_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final CheckListItem item = checkListItems.get(position);
holder.title.setText(item.getTitle());
holder.budget.setText(item.getBudget());
status = item.getStatus();
if(status.equals("1"))
{
holder.checkBox.setChecked(true);
}
if(status.equals("0")) {
holder.checkBox.setChecked(false);
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
status = "1";
HashMap<String, String> params = new HashMap<String, String>();
params.put("checklistItemId", item.getCheckListItemId());
params.put("budget",item.getBudget());
params.put("text", item.getTitle());
params.put("time_due", item.getDateTime());
params.put("reminder",item.getReminder());
params.put("status", status);
new UpdateCheckListItemsAsyncTask(context).execute(params);
} else
{
status = "0";
HashMap<String, String> params = new HashMap<String, String>();
params.put("checklistItemId", item.getCheckListItemId());
params.put("budget",item.getBudget());
params.put("text", item.getTitle());
params.put("time_due", item.getDateTime());
params.put("reminder",item.getReminder());
params.put("status", status);
new UpdateCheckListItemsAsyncTask(context).execute(params);
}
}
});
holder.bind(checkListItems.get(position), listener);
}
@Override
public int getItemCount() {
return checkListItems.size();
}
}
What's going wrong here? How can I save the position of checkbox?
Thank you..
I Had faced a similar Issue.
The thing is, in the RecyclerView, the ViewHolder is Recycled. So, until you remove the OnCheckedChangeListener
, the Items will refer to the old OnCheckedChangeListener.
if(status.equals("1"))
{
holder.checkBox.setChecked(true);
}
if(status.equals("0")) {
holder.checkBox.setChecked(false);
}
These lines actually triggers the old onCheckedChangedListener.
You can try this.
holder.checkBox.setOnCheckedChangeListener(null);
as the first Line of onBindViewHolder
onCheckedChanged
logic to that interface call using getLayoutPosition()
As to your second question,
you can use HashSet
to store the data of checked list item.
Your way of storing it in class object is also fine
EDIT- Added Code for reference
public class CheckListItemAdapter extends RecyclerView.Adapter<CheckListItemAdapter.MyViewHolder> {
...
..
public CheckListItemAdapter(List<CheckListItem> checkListItems, Context context, OnItemClickListener listener) {
this.checkListItems = checkListItems;
this.context = context;
this.listener = listener;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
....
....
if(item.getStatus().equals("1"))
{
holder.checkBox.setChecked(true);
}
else {
holder.checkBox.setChecked(false);
}
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
budget = (TextView) view.findViewById(R.id.budget);
checkBox = (CheckBox) view.findViewById(R.id.checkBox);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int pos = getLayoutPosition();
CheckListItem currentItem=checkListItems.get(pos);
//to remove redundant calls to network while scrolling
if ( isChecked){
if (currentItem.getStatus().equals("1")) {
return;
} else {
currentItem.setStatus("1");
}
} else {
if (currentItem.getStatus().equals("0")) {
return;
} else {
currentItem.setStatus("0");
}
}
//network call, when check is changed
checkChangedLogic(checkListItems.get(pos), isChecked);
}
});
}
}
Note-
I have implemented a simple logic in onCheckedChanged
to remove redundant calls. Since you mentioned they are network calls, this is necessary.