notifyDataSetChanged не может обновить ListView

У меня есть DialogFragment, который имеет представление списка с CheckedTextView и флажок вверху, чтобы проверить и снять отметку со всех элементов в представлении списка. Я пытаюсь установить для состояния CheckedTextView значение Checked/Unchecked в зависимости от состояния флажка CheckAll. Но я не могу соответствующим образом обновить представление, используя notifyDataSetChanged. введите здесь описание изображения

КатегорииDialogFragment.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;
        }
    }
}

Категория.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" />



Ответы (2)


Я пытаюсь установить для состояния CheckedTextView значение Checked/Unchecked в зависимости от состояния флажка CheckAll. Но я не могу соответствующим образом обновить представление, используя notifyDataSetChanged.

Добавил образец с кодом вопроса в качестве примера моих ответов. Он работает, и его можно найти здесь (посмотрите на него).

Кроме того, ответ Android-разработчика работает, потому что вы в основном сбрасываете адаптер с новыми элементами с правильным состоянием каждый раз, когда пользователь проверяет/снимает все CheckBoxs. Это может быть расточительно (но приемлемо, если список относительно небольшой). Также имейте в виду, что если categoryName класса Category изменится в диалоговом окне, вам нужно будет убедиться, что вы создаете новый Categories с правильным именем (если вы не изменяете имя категории, это не проблема) когда действуют все CheckBox.

Попробуйте что-то вроде этого:

  1. удалите categoriesListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);, если он есть в вашем коде
  2. измените OnCheckedChangeListener для проверки всех CheckBox следующим образом:

            @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. добавьте OnItemClickListener в свой categoriesListView ListView следующим образом:

                    @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. setChecked(boolean) и getCheckStatus() (я вижу, что у вас есть метод isChecked в Category, который вы могли бы использовать для получения логического статуса) — это методы в вашем классе Category для установки и получения статуса этого элемента

  5. в методе getView() адаптера установите статус следующим образом:

    holder.categoryName.setChecked(mCategories.get(position)
                    .getCheckStatus());
    
person user    schedule 03.01.2013
comment
Обновил код. я изменил category_state на логическое значение, которое будет храниться в данных. true означает проверено и наоборот. Теперь, когда я загружаю диалоговое окно, я включаю состояние на основе isChecked(). В соответствии с вашим кодом при нажатии проверить все, что я добавил код. но пользовательский интерфейс не отражает проверенное и непроверенное состояние. Но в журнале он показывает правильное значение. с notifyDataSetChanged я не могу обновить пользовательский интерфейс. - person Harsha M V; 04.01.2013
comment
@HarshaMV Как выглядит ваш макет строк? У вас есть один CheckedTextView или CheckTextView заключен в LinearLayout, как в предыдущем вопросе? - person user; 04.01.2013
comment
@HarshaMV Ты видел мою правку? Это сработало? Если нет (но должно), можете ли вы объяснить, как именно должны вести себя флажки? - person user; 05.01.2013
comment
извините, я пропустил редактирование. я пробовал, но все та же проблема. Когда я устанавливаю или снимаю флажок CheckAll, элементы списка не отражают изменения в пользовательском интерфейсе, чтобы стать отмеченными или снятыми. прикрепляю APK: play.mink7.com/Nomad.apk на случай, если вы не понимаете, что происходит . Щелкните второй значок на панели действий, чтобы открыть диалоговое окно. - person Harsha M V; 05.01.2013
comment
@HarshaMV Мой код должен был сработать. Я проверил это, и это работает (но, возможно, я неправильно понимаю ваш вопрос). Я отредактировал свой ответ и опубликовал небольшой образец, проверьте его с вашим кодом, возможно, вы не полностью реализовали мой ответ. - person user; 05.01.2013
comment
можете ли вы объяснить мне этот код adapter.getItem(i).setChecked(isChecked); я запутался, как это переключает состояние проверки и непроверенности - person Harsha M V; 05.01.2013
comment
ах извини!! понятно. Я устанавливал его в ListView вместо адаптера. Неудивительно, что он не обновлялся в пользовательском интерфейсе. - person Harsha M V; 05.01.2013
comment
@HarshaMV С помощью этого кода вы изменяете все состояния, хранящиеся в элементах Category адаптера. Если вы отметите все CheckBox, это поместит true в статус каждого элемента Category из строк адаптера. Затем вы вызовете notifyDataSetChanged, и это сообщит адаптеру, что ему необходимо перерисовать, и это покажет новые значения состояния, и все флажки из диалогового окна должны быть отмечены в этот момент. - person user; 05.01.2013
comment
Вот это да. ТАК не позволяет мне награждать Баунти в течение 24 часов :P Большое спасибо, приятель :D Извини, что преследовал тебя последние два дня :D - person Harsha M V; 05.01.2013
comment
@HarshaMV Нет проблем. Удачи с приложением, оно красивое. - person user; 05.01.2013

Итак, вы пытаетесь установить все свои элементы, проверенные на вашем

setOnCheckedChangeListener

насколько я понимаю. Прежде всего, если вы хотите сделать свой

adapter.notifyDataSetChanged();

для работы вы должны внести изменения в свое содержимое. Ты используешь

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

чтобы заполнить ваш диалог и обновить его, вы должны использовать тот же диалог с измененными данными или создать новый адаптер. Чтобы использовать тот же самый в вашем setOnCheckedChangeListener, вам нужно сделать что-то вроде этого:

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

        }
    });

Попробуйте это и дайте мне сейчас, если это работает для вас. :)

person hardartcore    schedule 05.01.2013
comment
Идеально. Большое спасибо помогло. просто чтобы понять, что я делаю не так. почему я не должен был уведомить раньше? - person Harsha M V; 05.01.2013