notifyDataSetChanged fails to update ListView
F

2

6

I have a DialogFragment which has a list view with CheckedTextView and a checkbox at the top to Check and uncheck all the items in the list view. I am trying to set the State of the CheckedTextView to Checked/Unchecked depending on the state of the CheckAll Check box. But i am not able to update the view accordingly using notifyDataSetChanged. enter image description here

CategoriesDialogFragment.java

public class CategoriesDialogFragment extends SherlockDialogFragment {
    CheckBox checkAll;
    ListView categoriesListView;
    CategoriesListAdapter adapter;
    static Category category;

    String[] categories = new String[] { "Hill Station", "Beach", "Historic",
            "Wild Life", "Waterfall", "River", "Archeology", "Hill Station",
            "Beach", "Historic", "Wild Life", "Waterfall", "River",
            "Archeology" };
    Boolean[] categories_state = new Boolean[] { true, false, true, true, true,
            true, false, true, false, true, true, true, true, false };

    public static CategoriesDialogFragment newInstance() {
        CategoriesDialogFragment frag = new CategoriesDialogFragment();
        Bundle args = new Bundle();
        frag.setArguments(args);
        return frag;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Dialog dialog = new Dialog(MainActivity.context);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

        dialog.setContentView(R.layout.dialog_categories);

        categoriesListView = (ListView) dialog
                .findViewById(R.id.listViewDialog);

        List<Category> theCategories = new ArrayList<Category>();
        for (int i = 0; i < categories.length; i++) {
            Boolean flag;
            Category pl = new Category(categories[i], categories_state[i]);
            theCategories.add(pl);
        }

        // categoriesListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        adapter = new CategoriesListAdapter(MainActivity.context,
                R.layout.dialog_list_item_category, theCategories);

        categoriesListView.setAdapter(adapter);

        // List View Item Click Listener
        categoriesListView
                .setOnItemClickListener(new AdapterView.OnItemClickListener() {

                    @Override
                    public void onItemClick(AdapterView<?> parent, View view,
                            int position, long id) {
                        // TODO Auto-generated method stub
                        CategoriesListAdapter adapter = (CategoriesListAdapter) parent
                                .getAdapter();
                        Category c = (Category) adapter.getItem(position);
                        c.setChecked(!c.getChecked());
                        adapter.notifyDataSetChanged();
                    }

                });


        // CheckAll CheckBox
        checkAll = (CheckBox) dialog.findViewById(R.id.checkBoxAll);
        checkAll.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {

                Toast.makeText(MainActivity.context, "Check",
                        Toast.LENGTH_SHORT).show();
                for (int i = 0; i < adapter.getCount(); i++) {
                    categoriesListView.setItemChecked(i, isChecked);
                    Log.i("Nomad", isChecked + " isChecked " + i);
                }
                adapter.notifyDataSetChanged();

                /*
                 * if (isChecked) { Log.i("Nomad", "isChecked"); for (int i = 0;
                 * i < adapter.getCount(); i++) { category = adapter.getItem(i);
                 * category.setChecked(true); Log.i("Nomad", "isChecked "+i); }
                 * adapter.notifyDataSetChanged(); } else { Log.i("Nomad",
                 * "isUnChecked"); for (int i = 0; i < adapter.getCount(); i++)
                 * { category = adapter.getItem(i); category.setChecked(false);
                 * Log.i("Nomad", "isUnChecked "+i); }
                 * adapter.notifyDataSetChanged(); }
                 */

            }
        });
        return dialog;

    }

    private static class CategoriesListAdapter extends ArrayAdapter<Category> {
        public Context mContext;

        List<Category> mCategories;

        public CategoriesListAdapter(Context context, int resource,
                List<Category> categories) {
            super(context, resource, categories);
            // TODO Auto-generated constructor stub
            this.mCategories = categories;
            this.mContext = context;

        }

        public int getCount() {
            return mCategories.size();
        }

        @Override
        public Category getItem(int position) {
            // TODO Auto-generated method stub
            return mCategories.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;

            if (convertView == null) {
                LayoutInflater viewInflater;
                viewInflater = LayoutInflater.from(getContext());
                convertView = viewInflater.inflate(
                        R.layout.dialog_list_item_category, null);

                holder = new ViewHolder();
                holder.categoryName = (CheckedTextView) convertView
                        .findViewById(R.id.categories_checkbox);

                convertView.setTag(holder);

            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            holder.categoryName.setText(mCategories.get(position)
                    .getCategoryName());
            holder.categoryName.setChecked(mCategories.get(position)
                    .getChecked());

            return convertView;
        }

        static class ViewHolder {
            CheckedTextView categoryName;
        }
    }
}

Category.java

public class Category {
    String categoryName = "";
    private boolean checked = false;

    public Category(String categoryName, boolean checked) {

        this.categoryName = categoryName;
        this.checked = checked;

    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public boolean getChecked() {
        return checked;
    }

    public void setChecked(boolean checked) {
        this.checked = checked;
    }

}

dialog_categories.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dip"
    android:layout_marginStart="8dip"
    android:background="@color/primary_white"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/title_template"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dip"
        android:layout_marginStart="16dip"
        android:gravity="center_vertical|start"
        android:orientation="horizontal"
        android:paddingTop="5dp" >

        <TextView
            android:id="@+id/textView1"
            style="?android:attr/textAppearanceLarge"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingLeft="10dp"
            android:text="@string/dialog_category_title"
            android:textColor="@color/primary_color"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/all"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/dialog_category_checkbox"
            android:textColor="@color/primary_color" />

        <CheckBox
            android:id="@+id/checkBoxAll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingRight="6dp" />
    </LinearLayout>

    <View
        android:id="@+id/titleDivider"
        android:layout_width="match_parent"
        android:layout_height="2dip"
        android:background="@color/black" />

    <LinearLayout
        android:id="@+id/contentPanel"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:minHeight="64dp"
        android:orientation="vertical" >

        <ListView
            android:id="@+id/listViewDialog"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
        </ListView>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/buttonPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <Button
            android:id="@+id/button_category_ok"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/dialog_category_btn_ok"
            android:textSize="14sp" />
    </LinearLayout>

</LinearLayout>

dialog_list_item_category.xml

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/categories_checkbox"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
    android:gravity="center_vertical"
    android:onClick="toggle"
    android:paddingBottom="10dp"
    android:paddingLeft="10dp"
    android:paddingRight="12dp"
    android:paddingTop="10dp"
    android:text="sss" />
Fabric answered 3/1, 2013 at 11:11 Comment(0)
D
2

I am trying to set the State of the CheckedTextView to Checked/Unchecked depending on the state of the CheckAll Check box. But i am not able to update the view accordingly using notifyDataSetChanged.

Added a sample with the question's code to as an example of my answers. It works and can be found here(have a look at it).

Also, Android-Developer's answer works because you'll basically reset the adapter with new items with the correct state each time the user checks/unchecks the all CheckBoxs. This could be wasteful(but acceptable if the list is relatively small). Also keep in mind that if the categoryName of the Category class changes in the dialog you'll need to make sure you construct the new Categories with the correct name(if you don't modify the category name then this isn't an issue) when the all CheckBox is acted upon.

Try something like this:

  1. remove the categoriesListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); if it's in your code
  2. modify the OnCheckedChangeListener for the check all CheckBox like this:

            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
    
                Toast.makeText(getActivity(), "Check", Toast.LENGTH_SHORT)
                        .show();
    
                Log.i("Nomad", "isChecked");
                for (int i = 0; i < adapter.getCount(); i++) {
                    adapter.getItem(i).setChecked(isChecked);
                    Log.i("Nomad", "isChecked " + i);
                }
                adapter.notifyDataSetChanged();
            }
    
  3. add an OnItemClickListener to your categoriesListView ListView like this:

                    @Override
                    public void onItemClick(AdapterView<?> arg0, View arg1,
                            int arg2, long arg3) {
                        CategoriesListAdapter adapter = (CategoriesListAdapter) arg0
                                .getAdapter();
                        Category c = (Category) adapter.getItem(arg2);
                        c.setChecked(!c.getCheckStatus());
                        adapter.notifyDataSetChanged();
                    }
    
  4. the setChecked(boolean) and getCheckStatus()(I see that you have a isChecked method in Category you could use that for getting the boolean status) are methods in your Category class for setting and getting the status of that item

  5. in the getView() method of the adapter, set the status like this:

    holder.categoryName.setChecked(mCategories.get(position)
                    .getCheckStatus());
    
Documentation answered 3/1, 2013 at 14:49 Comment(10)
Updated the code. i changed the category_state to boolean value which is how it will be stored in the data. true means checked and viceversa. Now when i load the Dialog i am enabling the state based on isChecked(). As per your code on clicking check all i added the code. but the UI doesnt reflect the checked and unchecked state. But on Log it shows the right value. with notifyDataSetChanged am not able to update the UI.Fabric
@HarshaMV How does your row layout looks like? Do you have a single CheckedTextView or is a CheckTextView wrapped by a LinearLayout like in your previous question?Documentation
@HarshaMV Did you see my edit? Did it worked? If not(but it should) can you explain exactly how the checkboxes should behave?Documentation
sorry i had missed the edit. i tried it but still the same problem. When i check or uncheck the CheckAll checkbox the listview items dont reflect the change in the UI to become checked or unchecked. attaching the APK: play.mink7.com/Nomad.apk just incase u dont understand whats happening. Click the second icon in the Actionbar to access the dialog.Fabric
@HarshaMV My code should have worked. I tested it and it works(but maybe I'm misunderstanding your question). I edited my answer and posted a small sample, check it against your code, maybe you didn't fully implement my answer.Documentation
can you explain me this code adapter.getItem(i).setChecked(isChecked); i am confused how does this toggle the check and unchecked stateFabric
ah sorry!! got it. I was setting it to the ListView instead of the Adapter. No wonder it was not getting refreshed on the UI.Fabric
@HarshaMV With that code you're modifying all the states stored in the Category items of the adapter. If you check the all CheckBox this will put true in the status of each Category item from the adapter rows. You'll then call notifyDataSetChanged and this will announce the adapter that it needs to redraw and this will show the new status values and all the CheckBoxes from the Dialog should be checked at this moment.Documentation
wow. SO doesnt allow me to award Bounty for 24 hours :P thanks a lot buddy :D sorry was chasing you for the last two days :DFabric
@HarshaMV No problem. Good luck with the app, it looks nice.Documentation
R
2

So you are trying to set all your items checked on your

setOnCheckedChangeListener

as I understand. First of all, if you want to make your

adapter.notifyDataSetChanged();

to work you have to make edits on your contents. You are using

List<Category> theCategories = new ArrayList<Category>();

to populate your dialog and to update it you have to use the same one with changed data or create a new adapter. To use the same one in your setOnCheckedChangeListener you have to do something like this :

checkAll.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            if(isChecked){
              theCategories.clear();
              Toast.makeText(MainActivity.context, "Check", Toast.LENGTH_SHORT).show();
              for (int i = 0; i < categories.length; i++) {
                  Category pl = new Category(categories[i], true);
                  theCategories.add(pl);
              }
              adapter.notifyDataSetChanged();
           }

        }
    });

Try this and let me now if it works for you. : )

Ranna answered 5/1, 2013 at 11:35 Comment(1)
Perfect. Thanks a lot it helped. just to understand what i was doing wrong. why was i not to notify before ?Fabric

© 2022 - 2024 — McMap. All rights reserved.