0

I have been using a ListView with each item a CheckableLinearLayout as defined in

CheckableLinearLayout

I cannot check any row in the ListView, it does not even register the check in the UI. I do not believe there is a android:checkMark for the CheckableLinearLayout. Is it correct to nest the CheckedTextView inside my CheckableLinearLayout, would it be better if I used a CheckBox instead. Also, how can I put them in the ArrayList as soon as they are checked, instead of iterating over them in this manner.

This is my layout:

   <com.example.deltest.CheckableLinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 >
<CheckedTextView 
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
 />
<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:id="@+id/txt_a"
          />
<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:id="@+id/txt_b"
    />

   </com.example.deltest.CheckableLinearLayout>

I have implemented the listActivity as follows:

    public class DeleteList extends ListActivity 
    {
    ArrayList<Integer> idList=new ArrayList<Integer>();
    Cursor  c;
    Handler handler;
    static final int WHAT=0;
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    final TumblrDB db=new TumblrDB(this);
    c=db.query();
    startManagingCursor(c);
    handler=new Handler();
    View v=getLayoutInflater().inflate(R.layout.layout_header, null,false);
    getListView().addHeaderView(v);
    getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.layout_del,c,new String[] {TumblrDB.DATE,TumblrDB.DESC},new int[]{R.id.txt_a,R.id.txt_b});
    getListView().setAdapter(adapter);
    if(handler.hasMessages(WHAT))
    {
        c=db.query();
        ((SimpleCursorAdapter)getListView().getAdapter()).swapCursor(c);
    }

    Button btn_del=(Button)v.findViewById(R.id.btn_del);
    btn_del.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View view) {
            // TODO Auto-generated method stub
            int count=getListView().getCount();
            SparseBooleanArray sparseBooleanArray=getListView().getCheckedItemPositions();
            for(int i=0;i<count;i++)
            {
                if(sparseBooleanArray.get(i))
                {
                    c.moveToPosition(i);
                    int _id=c.getInt(c.getColumnIndex(TumblrDB._ID));
                    Log.d("DeleteList", "The id has been added "+_id);
                    idList.add(_id);
                    new Thread()
                    {
                        public void run()
                        {
                            for(int i:idList)
                            {
                                db.delete(i);
                                Log.d("DeleteList", "The id has been deleted "+i);
                                handler.sendEmptyMessage(WHAT);
                            }
                        }
                    }.start();
                }
            }
        }

    });

}   

 }

EDIT Trying a different approach to solve the problem by extending SimpleCursorAdapter:

    if(row==null)
    {
        row=inflater.inflate(layout, null, false);
        holder=new ViewHolder(row,position);
        row.setTag(holder);
        holder.check_del.setTag(position);
    }
    else
    {
        holder=(ViewHolder)row.getTag();
        holder.check_del.setOnClickListener(null);
        holder.check_del.setTag(position);
        if(hitList.get(position))
            holder.check_del.setChecked(true);
        else
            holder.check_del.setChecked(false);
    }

Then I have implemented an OnClickListener for the CheckBox:

      OnClickListener cbl=new OnClickListener(){

        @Override
        public void onClick(View view) {
            // TODO Auto-generated method stub
            int position=(Integer)view.getTag();
            Log.d("CustomCursorAdapter", "The checkbox at postion "+position+" has been clicked");
            if(((CheckBox)view).isChecked())
            {
                hitList.set(position, true);
            }
            else 
            {
                hitList.set(position, false);
            }
        }
    };  

Now when I try to access the ArrayList that I am using,it throws an ArrayOutOfBoundsException:

    btn_del.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View view) {
            // TODO Auto-generated method stub
            new Thread()
            {
                public void run()
                {
                    int count=lv.getCount();
                    for(int i=0;i<count;i++)
                    {
                        if(adapter.hitList.get(i))
                        {
                            db.delete(c.getInt(c.getColumnIndex(TumblrDB._ID)));
                        }
                    }
                }
            }.start();
            adapter.notifyDataSetChanged();
        }
    });
6
  • I have no idea what a CheckableLinearLayout is but if you're trying to choose multiple items from a list then you could accomplish it using CheckBox. You could write a custom adapter for the ListView and in its getView method attach an onCheckedChangedListener to the item's CheckBox and add/remove that item from the ArrayList of chosen items depending on the checked state of the item. Commented Oct 7, 2013 at 8:06
  • When doing that by overriding the newView and bindView methods,if a checkbox has checked,other checkboxes are automatically checked,if I use checkBox=null and/or checkBox.setChecked(false) to mitigate this,I find that the checkBox I previously checked gets unchecked when the view is recycled.Can you show me some code/explain how I can prevent these side-effects when extending SimpleCursorAdapter Commented Oct 7, 2013 at 9:36
  • Do I need to add a ListView.OnClickListener to this to make these items clickable. Commented Oct 7, 2013 at 11:42
  • Before reusing an existing CheckBox if you don't detach it's onCheckedChangeListener then when setting the checked state for it the previous listener will be called. to avoid this before reusing the view call SetonCheckedChangeListener(null) then set the checked state and then attach the new checkchange listener. If you want to make the List item clickable then you should add an onListItemClickListener and in the root of your list item's layout add android:descendantFocusability="blocksDescendants" so that the CheckBox doesn't steal the focus from the list item. Commented Oct 7, 2013 at 12:24
  • posted an Edit based on your recommendations,have overridden getView of SimpleCursorAdapter.Now,when I try to access the ArrayList<boolean> from the ListActivity it throws an ArrayOutOfBoundsException. Commented Oct 7, 2013 at 12:55

1 Answer 1

1

Using an ArrayList to store the state of all the checkboxes in the list.

   public static ArrayList<Boolean> hitList;

I have initialized and set all values to false:

    hitList=new ArrayList<Boolean>();
    for(int i=0;i<this.getCount();i++)
    {
        hitList.add(i, false);
    } 

When,initializing the checkbox for a View,it looks in the array by position and checks it only if the value in the ArrayList is true.The position is held by the CheckBox using it's setTag method and retrieved within the Listener to determine the position of the checkbox which has been checked.

   @Override
public View getView(int position,View convertView,ViewGroup parent)
{
    View row=convertView;
    ViewHolder holder;

    if(row==null)
    {
        row=inflater.inflate(layout, null, false);
        holder=new ViewHolder(row);
        row.setTag(holder);
        holder.check_del.setTag(position);
    }
    else
    {
        holder=(ViewHolder)row.getTag();
        holder.check_del.setOnClickListener(null);
        holder.check_del.setTag(position);
        if(hitList.get(position))
            holder.check_del.setChecked(true);
        else
            holder.check_del.setChecked(false);
    }
    c.moveToPosition(position);
    holder.txt_a.setText(c.getString(c.getColumnIndex(ItemDB.TITLE)));
    holder.txt_b.setText(c.getString(c.getColumnIndex(ItemDB.DESCRIPTION)));

    OnClickListener cbl=new OnClickListener(){

        @Override
        public void onClick(View view) {
            // TODO Auto-generated method stub
            int position=(Integer)view.getTag();
            Log.d("CustomCursorAdapter", "The checkbox at postion "+position+" has been clicked");
            if(((CheckBox)view).isChecked())
            {
                hitList.set(position, true);
            }
            else 
            {
                hitList.set(position, false);
            }
        }
    };  

    holder.check_del.setOnClickListener(cbl);
    return row;
}

static class ViewHolder
{
    TextView txt_a;
    TextView txt_b;
    CheckBox check_del;
    ViewHolder(View row)
    {
        txt_a=(TextView)row.findViewById(R.id.txt_a);
        txt_b=(TextView)row.findViewById(R.id.txt_b);
        check_del=(CheckBox)row.findViewById(R.id.check_del);
    }
}

Currently,I have a header in the ListView which has the following onClickListener:

    @SuppressWarnings("deprecation")
        @Override
        public void onClick(View view) {
            // TODO Auto-generated method stub
            ArrayList<Boolean> killList=CustomCursorAdapter.hitList;
            int totalDeleted=0;
            for(int i=0;i<killList.size();i++)
            {
                //Log.d(TAG,i+":"+killList.get(i));
                c.moveToPosition(i);
                String title=c.getString(c.getColumnIndex(ItemDB.TITLE));
                int _id=c.getInt(c.getColumnIndex(ItemDB._ID));
                //Log.d(TAG, "Item has title "+title+" and id "+_id );
                int rowsAffected=0;
                if(killList.get(i))
                {
                    rowsAffected=db.delete(_id);
                    //Log.d(TAG, "Deleted row with id "+_id);
                    killList.set(i, false);

                }
                totalDeleted+=rowsAffected;

            }
            //Log.d(TAG, "The total number of rows deleted "+totalDeleted);
            //if(c.requery())
            //{
                //Log.d(TAG, "Requerying data,this calls notifyDataSetChanged");
            //}

        }});

Once,you have deleted data from the row,before you call requery on the Cursor(which is deprecated...need to find a better alternative),the values in the ArrayList have to be reset.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.