tags:

views:

407

answers:

3

I have list of checkboxes in list binded by Custom simpleCurserAdapter. in my Custom simpleCurserAdapter ive override the newview and binview with my modifications. ive managed somehow to do multichoice.. wierd thing after i delete any item from my list , the first item's checkbox is being checked all of a sudden.. how does that happen? how can i solve it?

Thanks code: my curser SimpleCursorAdapter class:

             public class MyListCursorAdapter extends SimpleCursorAdapter

              {
                      private Context context;
                       private int layout;

                     public MyCursorAdapter(Context context, int layout, Cursor c,
                     String[] from, int[] to)
                         {
                                super(context, layout, c, from, to);

                               this.context = context;

                                this.layout = layout;

                               }

                               @Override
                               public View newView(Context context, Cursor cursor, ViewGroup parent)

{

                                Cursor c = getCursor();

                            final LayoutInflater inflater = LayoutInflater.from(context);
                             View v = inflater.inflate(layout, parent, false);
                            CheckBox chkBoxBtn = (CheckBox) v.findViewById (R.id.deleteTwittChkBox);
                            if (chkBoxBtn != null)
                             {
                                    chkBoxBtn.setChecked(false);
                             }

                              return v;

                    }

@Override public void bindView(View v, Context context, Cursor c) {

               --binding view to my textsview in my items

                //now it's the importat part:

                 CheckBox chkBoxBtn = (CheckBox) v.findViewById(R.id.deleteTwittChkBox);
                if (chkBoxBtn != null)
                  {
                        chkBoxBtn.setId(Integer.valueOf(c.getString(c
                    .getColumnIndex(MyUsers.User._ID))));
                     chkBoxBtn.setOnClickListener(new OnItemClickListener(chkBoxBtn, v));
                      chkBoxBtn.setChecked(false);
                 }
         }

//i couldnt find another way of doing this, but this is how i set listeners to my checkboxses

            static ArrayList<String> checkedItemsList = new ArrayList<String>();

              private class OnItemClickListener implements OnClickListener
                {

                            private int mPosition;
                            private CheckBox chkBox;

                            OnItemClickListener(CheckBox mChkBox, View v)
                                  {

                                          chkBox = mChkBox;
                                        chkBox.setChecked(false);
                                    }


                      @Override
                       public void onClick(View v)
                      {
                          if (chkBox.isChecked())
                           {
                                checkedItemsList.add(String.valueOf(chkBox.getId()));
                            }
                          else
                            {
                                    checkedItemsList.remove(String.valueOf(chkBox.getId()));
                             }

                       }




             }

        }

okie now this is code part from the ListActivity class which desbribes the button which deleting the checked Box items

               OnClickListener btListener = new OnClickListener()
                 {
                          public void onClick(View view)
                     {

                              // long[] items = listView.getCheckItemIds();
                                int x = 0;
                                Uri myUri = Uri
                              .parse("content://com.idan.datastorageprovider/users");
                             String where = "_id" + "=?";
                      //here i am tatking all checkboxes which ive added from the  adapter class
                            ArrayList<String> checkedItemsList =   MySimpleCursorAdapter.checkedItemsList;
                            for (String itemID : checkedItemsList)
                               {
                                      getContentResolver()
                                     .delete(myUri, where, new String[] { itemID});
                                     checkedItemsList.remove(itemID);
                                      }


                              }
                     };
A: 

You might need to call notifyDataSetChanged when you modify the data.

Segfault
In which place please?
Moshik
ive added it after the OnClickListener btListener = new OnClickListener() function and still it didnt make any diffrence, the first checkbox of the first item is being checked unexpectedly!
Moshik
A: 

The problem is probably that you're calling setChecked from within the onItemClickListener. One hacky way around this is to do the following before and after you call setChecked from within your listener:

chkBox.setClickable(false);
chkBox.setChecked(false);
checkBox.setClickable(true);

This will prevent your onItemClickListener from getting called when you manually call setChecked.

Mike
ive tried to add the clickable (false) and clickable(true) be4 and after, but still didnt do the trick..
Moshik
+1  A: 

I doubt that SimpleCursorAdapter is the right class to extend here.

Is the "checked" state connected to the data XML in any way? No? So you need your own custom adapter!

Basically all adapters have to implement a way to generate a view from a given element (more precisely an element position!). This will be called at any time where the list wants to display an element. Now, the trick it uses is to re-use formerly created list view elements that cannot be seen on screen any more! Thus: when you scroll your list down and an element disappears at the top, EXACTLY this view object will be re-used for the next appearing item.

So, when this method is called with a given "old" view that should be re-used, all contained elements will have to be set according the elements data. If a checkbox is part of this game, you will have to have a storage for the checked state! It is not sufficient to have a checkbox as there will be less checkbox objects as there are list elements!

SimpleCursorAdapters are there to - yeah - represent SIMPLE things. An XML describing data (images and text, as the documentation states). Because of this simplicity all you have to do here is provide a method to create NEW element view objects - you are not intercepting the re-use process AT ALL! It basically only knows how to put the data into an existing view object - but it is lacking the knowledge of how to handle checked/unchecked boxes!

Your solution: write your own BaseAdapter extension and do what has to be done: implement "getView" (and some other methods like getItem, getItemId and getCount). It's not hard at all! This API Demo uses a BaseAdapter and the mExpanded state here is basically identical to your checkbox states!

Good luck!

Zordid
i used to use BaseAdapter, but ive been told sometime later that simpleCurserAdapter is the most efficient way to use when you binding data from DATABASE!
Moshik
no matter what the source is: is checking of a check box **directly** tied to this database, i.e. is the state of these checkboxes stored within your database? If not: it's just as I described - **you** have to manually "remember" the check state of each item in some way and **you** have to restore it each time a view object is reused for a different data element.Regarding your question: what does "checked unexpected" really mean? Try to see **which** item is removed from the displayed elements. The checked state comes from a re-used "old" view element, I am really sure!
Zordid
Yes you right, i though mybe this will be good idea.. to create new ArrayList, that will hold all current checkboxes, and everytime in my view, to reset all those checkboxes state to false.and yes my checkboxes are not tied directly to my database, but the other elements in the item are. so ive been told i should switch to Simplecursor, so it will be more effective, coz with adapter it leaded me to allocate lots of objects.(each object to each item)about the checked state: it only happens when i delete the last elements, then the check state of the first element turning on unexpectdly
Moshik
The BaseAdapter-if implemented **correctly** -will always be the most efficient! So, if anybody told you to use SimpleCursorAdapter instead, and it really was "more efficient",that only means that **your** implementation was crap. ;-) If yours had one object per item - that was the mistake! In getView always re-use the given convertView (second paramter) and DO NOT instanciate a new view each time! Then, you will face exactly the same problem: you need storage for checked state: an array, a set, whatever! In the checkboxes listener you must then update that "state-memory" according to the pos!
Zordid
this is how it was:i had cursor which retriving the data row by row from my database, and putting it in an new object, each object symbolises item in the list of my items. so now we got another array list of object. now that list of objects i have to add to my adapter list(object by object). and with that adapter i am building my getView function...and this is the list i see on the screen. ill sum it: we got two array lists here.. the items ArrayList<item>, and the adapter ArrayAdapter<item>
Moshik
Please read that article and tell me what you think it's better:http://thinkandroid.wordpress.com/2010/01/13/an-analysis-between-baseadapters-and-cursoradapters/
Moshik
Gee, that's a heck of a lot information. But I still keep up my claim: a SimpleCursorAdapter **cannot** be any faster than a BaseAdapter, simply because a SimpleCursorAdapter **IS** a BaseAdapter, i.e. it is derived from it. (have a look at the inheritance here: http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html) So, in **any** custom written descendant of a BaseAdapter you can be as fast as a SimpleCursorAdapter.Your only "problem" is the management of the checked state - not more, not less.
Zordid
You right!!! and i am still struggle it.. and i couldnt find a way how to save the state.. i even dont need to save the state, on scrolling up/down it does save it's state in wierd way.. but it does.. the only prob is when i delete an item.. then it's crapping up! realy realy despert.. 3 days on it.. and nothing going on!
Moshik
how would you combine the data binding + saving checkboxes state + being efficient, could you write something .. some code according to my code above? ill realy appreciate it!
Moshik
Because of your task to have two kinds of data, I would again strongly advise to start with a more basic class, `BaseAdapter` or maybe even `CursorAdapter` - as this is the most "natural" way to approach the task to display items from a cursor.The deeper you go in the inheritance tree - BaseAdapter->CursorAdapter->ResourceCursorAdapter->SimpleCursorAdapter, the "easier" it will be to accomplish simple tasks, but the less flexibility you will have!I think,without coding a single line: the SimpleCursorAdapter might not be right,it takes away the freedom to manipulate elements on your own!
Zordid
I think i know what is my problem, not sure mybe u can explain that: after i delete an item the bindview method is being called again, and when it reach to this part: CheckBox chkBoxBtn = (CheckBox) v.findViewById(R.id.deleteTwittChkBox); chkBoxBtn is getting NULL!! how come?? the first time you get the data, it doest get some value, but after you delete, it gets null, mybe here it's the prob? any idea?
Moshik
it's like all the rest of the views(textViews..) r fine, but when it's re-rending v.findViewById(R.id.deleteTwittChkBox) it's getting null.. coz it's checkbox and not textview? wierd thing!!
Moshik