Пример notifyDataSetChanged

Я пытаюсь использовать в своем Android Application метод notifyDataSetChanged() для ArrayAdapter, но у меня он не работает.

Я нашел здесь ответ здесь, что notifyDataSetChanged() должен выполняться в основном потоке, но для этого не было примера.

Может ли кто-нибудь прислать пример или хотя бы ссылку ?!


person Tima    schedule 08.09.2010    source источник


Ответы (5)


Для ArrayAdapter, notifyDataSetChanged работает, только если вы используете add(), insert(), remove() и clear() на адаптере.

Когда создается ArrayAdapter, он содержит ссылку на List, который был передан. Если бы вы должны были передать List, который был членом Activity, и позже изменить этот член Activity, ArrayAdapter по-прежнему будет содержать ссылку на оригинал List. Адаптер не знает, что вы изменили List в действии.

Ваш выбор:

  1. Используйте функции ArrayAdapter для изменения базового списка (add(), insert(), remove(), clear() и т. Д.)
  2. Повторно создайте ArrayAdapter с новыми данными List. (Использует много ресурсов и сборку мусора.)
  3. Создайте свой собственный класс, производный от BaseAdapter и ListAdapter, который позволяет изменять базовую структуру данных List.
  4. Используйте notifyDataSetChanged() каждый раз при обновлении списка. Чтобы вызвать его в потоке пользовательского интерфейса, используйте runOnUiThread() из Activity. Тогда notifyDataSetChanged() будет работать.
person jnosek    schedule 23.02.2011
comment
будьте осторожны и с назначением «новых» объектов вашим данным. вместо этого используйте clear (), повторно заполните / внесите изменения в данные, затем вызовите notifyDataSetChanged () - person moonlightcheese; 07.04.2011
comment
Но что, если мы назовем notifyDataSetChanged() таким образом: ((BaseAdapter) arrayAdapter).notifyDataSetChanged();? - person teoREtik; 26.01.2012
comment
Я использую BaseExpandableListAdapter, у него нет функций add () или remove (), поэтому я сохраняю свою карту как переменную-член. Я обновляю карту и вызываю notifyDatasetChanged (), но ничего не происходит. Когда я использую вариант №4, он работает. Почему??? - person emeraldhieu; 25.12.2012
comment
Я использую ArrayAdapter для пользовательского GridView, я добавляю изображения по мере их получения с URL-адресов, вызывая адаптер.add (dataReceived). Это отлично работает, добавляет данные, но почему это обновляется и идет наверх. Я хочу отображать элементы по мере их добавления без обновления списка. (Что нужно сделать, так это работать с Android GridView с помощью notifyDatasetChanged ()) Как я могу заставить его работать в этом customGridView (StaggeredGridView). - person MobileEvangelist; 15.05.2013
comment
Я попытался создать свой собственный BaseAdapter, чтобы добавить в список методы сортировки, но по какой-то причине это просто не сработало. Не то чтобы мое приложение работало медленно, даже если я воссоздаю весь адаптер с отсортированным массивом, но меня это все равно раздражает. Но как именно это создаст много мусора? Я предполагаю, что фактический массив дорогостоящих данных хранится в качестве ссылки в действии, вызывающем адаптер, то есть будет собираться только адаптер. - person G_V; 10.11.2014
comment
Я попробовал notifyDataSetChanged () внутри onPostExecute из AsyncTask, но это не сработало. Затем я использовал runOnUiThread () внутри onPostExecute, и это сработало. Кто-нибудь может сказать мне, почему. Я, хотя onPostExecute все равно работает в потоке пользовательского интерфейса. - person turtleboy; 17.12.2014
comment
если полезно, я нашел здесь прекрасный пример (супер простой): thedeveloperworldisyours.com/android/notifydatasetchanged - person Javier C. H.; 09.10.2018
comment
Помните, что при вызове notifyDataSetChanged() будет проверяться массив, объявленный in the adapter. Поэтому вам следует создать public метод в адаптере, например updateArrayList, который изменил бы объявленный массив. Не забудьте использовать ArrayList методы, такие какadd(), insert(), remove() или clear(), для обновления элементов. Также не забудьте обновить размер массива, который используется в getItemCount() в адаптере RecylerView. Параметр используется для определения номера строки RecyclerView. - person Alston; 07.06.2019

Вы можете использовать метод runOnUiThread(). следующее. Если вы не используете ListActivity, просто измените код, чтобы получить ссылку на ваш ArrayAdapter.

final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }
});
person Brian    schedule 08.09.2010
comment
Я попытался добавить ваш фрагмент кода в свой код (вы можете найти его здесь stackoverflow.com/questions/3667442/how-to-refresh-adapter) в методе onCreate, но у меня все еще нет успеха :( Может быть, это было неправильное место, чтобы добавить его ?! - person Tima; 08.09.2010
comment
Ваш вопрос просто спросил, как вы можете вызвать метод и запустить его в основном потоке пользовательского интерфейса. Это отвечает на этот вопрос. В вашем конкретном случае (stackoverflow.com/questions/3670500/) AsyncTask и его метод onPostExecute () кажутся тем, что вам следует учитывать. - person Brian; 09.09.2010

Я недавно писал на эту тему, хотя этот пост старый, я подумал, что он будет полезен тем, кто хочет знать, как реализовать BaseAdapter.notifyDataSetChanged() шаг за шагом и правильно.

Следуйте Как правильно реализовать BaseAdapter.notifyDataSetChanged () в Android или новый блог BaseAdapter.notifyDataSetChanged ().

person Arif Nadeem    schedule 15.02.2013
comment
Привет, я попробовал первый пример ссылки, но вместо mItem.add(), я просто отредактировал один элемент, значит, например, mItem.get(position).setImage(encodedImage) может быть поэтому он выдает ошибку NullPointer exeption. Так notifyDataSetChange работает, просто редактируя его, bcz для адаптера Array упоминается выше он работает только для add (), clear (), remove () и т. д. - person Shreekant N; 01.09.2015
comment
notifyDataSetChanged будет работать для редактирования или изменения набора данных, ваш нулевой указатель вызван чем-то другим, проверьте журналы. - person Arif Nadeem; 01.09.2015

У меня была та же проблема, и я предпочитаю не заменять весь ArrayAdapter новым экземпляром постоянно. Таким образом, у меня есть AdapterHelper, который выполняет тяжелую работу где-то еще.

Добавьте это туда, где вы обычно (пытаетесь) вызвать уведомление

new AdapterHelper().update((ArrayAdapter)adapter, new ArrayList<Object>(yourArrayList));
adapter.notifyDataSetChanged();

AdapterHelper класс

public class AdapterHelper {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void update(ArrayAdapter arrayAdapter, ArrayList<Object> listOfObject){
        arrayAdapter.clear();
        for (Object object : listOfObject){
            arrayAdapter.add(object);
        }
    }
}
person Kevin Parker    schedule 13.12.2011
comment
В моем коде есть пара других адаптеров ArrayAdapter, и они работают без проблем. Сегодня вечером я решил превратить SimpleCursorAdapter в ArrayAdapter, и он НЕ БУДЕТ РАБОТАТЬ. Поработав с этим несколько часов и пытаясь найти причину, по которой это не работает, я нашел ваш класс AdapterHelper, и ТЕПЕРЬ ЭТО РАБОТАЕТ! Спасибо! - person proudgeekdad; 08.07.2012
comment
Это легко сделать с помощью функции ... ПОЧЕМУ бы вы создали для нее экземпляр нового класса? - person techiServices; 09.08.2012
comment
В Java функции называются методами. Что бы вы предложили, возможно, иметь этот многократно используемый метод в том же классе, что и адаптер массива? Или фрагмент / действие, содержащий представление списка? Так что да, это в классе, где его можно использовать повторно. Если вы хотите сделать его статичным, продолжайте. - person Kevin Parker; 09.08.2012
comment
Хорошая идея. Другой вариант - расширить ArrayAdapter с именем ArrayAdapterCompat и переопределить метод addAll (..), поскольку он доступен только с API 11. Там проверьте уровень API и используйте super.addAll(..) для API ›11 и super.add (. .) в сочетании с итерацией, подобной вашей: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { super.addAll(items); } else { for (Object o : collection) { super.add(o); } }. Теперь просто расширьте свой новый класс адаптера. - person Konsumierer; 26.10.2012
comment
Идеально! Большое спасибо @Kevin - это было ТОЧНО то, что мне было нужно! - person Kibi; 15.02.2013
comment
@hey, Кевин, я не могу решить проблему с помощью этого метода, пожалуйста, сообщите - person Praneeth; 30.06.2015

Я знаю, что это запоздалый ответ, но я столкнулся с аналогичной проблемой, и мне удалось ее решить, используя notifyDataSetChanged() в нужном месте.

Итак, моя ситуация была следующей.

Мне пришлось обновить список на вкладке панели действий (фрагмент) с содержимым, возвращенным из совершенно другого действия. Однако вначале список изменений не отражал. Однако, когда я щелкнул другую вкладку, а затем вернулся на желаемую вкладку, список был обновлен с правильным содержанием из другого действия. Чтобы решить эту проблему, я использовал notifyDataSetChanged() адаптера панели действий в коде действия, которое должно было возвращать данные.

Это фрагмент кода, который я использовал в упражнении.

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) 
    {
        case R.id.action_new_forward:

            FragmentTab2.mListAdapter.notifyDataSetChanged();//this updates the adapter in my action bar tab
            Intent ina = new Intent(getApplicationContext(), MainActivity.class);
            ina.putExtra("stra", values1);
            startActivity(ina);// This is the code to start the parent activity of my action bar tab(fragment).
    }
}

Это действие вернет некоторые данные в FragmentTab2 и напрямую обновит мой список в FragmentTab2.

Надеюсь, кто-то сочтет это полезным!

person mutp    schedule 18.09.2014