Search code examples
androidandroid-listviewandroid-cursoradaptercustom-adapterandroid-checkbox

Listview with custom checkable rows backed by custom cursor adapter looses selection when recycling views


I know this question has been asked before but I have a spin on it that I just can't seem to find an elegant solution for.

How can I keep track of selected checkboxes in a listview which uses a custom checkable relative layout (which has a checkbox and other textviews) backed by a custom cursor adapter that can can change size depending on what the user clicks(it filters on the users choice).

I have my listview activity which uses a custom cursor adapter (with the appropriate overrides for the bindview and newview functions along with a viewHolder class to take advantage of view recycling).

When a user clicks on a row item the list is filtered and the loadmanager restarted to display the new filtered list. This means that my listview size is constantly changing. In addition, I tried to implement the whole checkbox onclicklistener override thing along with setting and getting tags but no matter what I do in my bindview() method the checkboxes don't get checked (could this be because they are within a checkable row). Also, I'm getting really confused with the whole checkbox onclicklistener override in the getview (or bindview method in my case) along with the fact that a lot of the solutions I have seen don't have listviews that constantly change size.

Any help would be greatly appreciated.

Here is my custom cursor adapter class.

    public class TaskListViewAdapter extends CursorAdapter {

    private LayoutInflater mLayoutInflater;

    public TaskListViewAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);

        mLayoutInflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        ViewHolder holder = (ViewHolder) view.getTag();
        int nTaskStatus;
        int nTaskType;
        int nSuite;
        String nTaskServiceTextColor;
        String nTaskServiceBackgroundColor;
        String nSuiteValue;

        if (holder == null)
        {
            // Creates a ViewHolder and store references to the children views we want to bind data to.
            holder = new ViewHolder();

            holder.taskScreenCheckBox = (CheckBox) view.findViewById(R.id.taskScreenCheckBox);
            holder.taskScreenRowText11 = (TextView) view.findViewById(R.id.taskScreenRowText11);

            view.setTag(holder);
        }

        // Getting the data from the cursor and setting the row elements appropriately
        if (cursor != null) {


            holder.taskScreenRowText11.setText(cursor.getString(cursor.getColumnIndex(DatabaseAdapter.KEY_TASKS_NUMEROAPPEL)));

        }
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        final View view = mLayoutInflater.inflate(R.layout.task_screen_row, parent, false);
        return view;
    }

    /**
     * 
     * 
     *         A viewholder that stores each component of the task_screen_row view.
     * 
     */
    static class ViewHolder {
        CheckBox taskScreenCheckBox;
        TextView taskScreenRowText11;

    }
}

Here is my custom Checkable row layout:

    package com.courrierplus.mobi;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Checkable;
import android.widget.RelativeLayout;

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {

    private CheckBox mCheckbox;

    public CheckableRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean isChecked() {
        return mCheckbox.isChecked();
    }

    @Override
    public void setChecked(boolean isChecked) {
        mCheckbox.setChecked(isChecked);
    }

    @Override
    public void toggle() {
        mCheckbox.toggle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        final int childCount = this.getChildCount();
        for (int i = 0; i < childCount; ++i) {

            View v = getChildAt(i);
            if (v instanceof CheckBox) {
                mCheckbox = (CheckBox) v;
            }
        }
    }
}

In my ListViewActivity the user click on a row, the onListItemClick function is called which then calls the newView code in my custom adapter which inflates my custom checkable row and checks the checkbox within it.

My issue is that within the bindView of my custom adapter when I get the checkbox and manually try to set it to checked it does not work. Also, I'm not sure how to keep track of what has been checked or not.


Solution

  • I have already faced similar issue in android. I think this can help you..

    How do I link a checkbox for every contact in populated listview?