androidandroid-listviewandroid-dialogfragmentcheckedtextviewnotifydatasetchanged

notifyDataSetChanged fails to update ListView


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" />

Solution

  • 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());