пример notifyDataSetChanged


166

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

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

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



Вы можете проверить этот блог и этот пример в GitHub и это также
Кабесас

Ответы:


328

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

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

Ваш выбор:

  1. Используйте Функции ArrayAdapterизменить основной список ( add(), insert(), remove(), clear()и т.д.)
  2. Создайте ArrayAdapterзаново с новыми Listданными. (Использует много ресурсов и сборку мусора.)
  3. Создайте свой собственный класс, производный от него BaseAdapterи ListAdapterпозволяющий изменять базовую Listструктуру данных.
  4. Используйте notifyDataSetChanged()каждый раз, когда список обновляется. Чтобы вызвать его в UI-Thread, используйте runOnUiThread()of Activity. Тогда notifyDataSetChanged()будет работать.

13
будьте осторожны и с назначением «новых» объектов вашим данным. вместо этого используйте clear (), заново заполняйте / вносите изменения в данные, затем вызывайте notifyDataSetChanged ()
moonlightcheese

Но что , если мы называем notifyDataSetChanged()таким образом ((BaseAdapter) arrayAdapter).notifyDataSetChanged();?
teoREtik

2
Я использую BaseExpandableListAdapter, у него нет функций add () или remove (), поэтому я храню свою Map как переменную-член. Я обновляю Map и вызываю notifyDatasetChanged (), но ничего не происходит. Когда я использую выбор № 4, это работает. Зачем???
Emeraldhieu

Я использую ArrayAdapter для пользовательского GridView, я добавляю изображения, когда получаю их из URL, вызывая adaptor.add (dataReceived). Это прекрасно работает, добавляет данные, но почему это освежает и идет наверх. Я хочу показать элементы по мере их добавления без обновления списка. (Что нужно сделать, так это работать с GridView Android с помощью notifyDatasetChanged ()). Как я могу заставить его работать в этом customGridView (StaggeredGridView).
MobileEvangelist

1
Я попытался создать свой собственный BaseAdapter, чтобы добавить методы сортировки в список, но по какой-то причине это просто не сработало. Не то чтобы мое приложение работало медленно, даже если я воссоздаю весь адаптер с помощью отсортированного массива, но это все равно раздражает меня. Как именно это создаст много мусора? Я предполагаю, что фактический массив дорогих данных хранится в качестве ссылки в действии, вызывающем адаптер, то есть будет собираться только адаптер.
G_V

34

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

final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }
});

1
Я пытался добавить фрагмент вашего кода в мой код (вы можете найти его здесь stackoverflow.com/questions/3667442/how-to-refresh-adapter ) в методе onCreate, но у меня все еще нет никакого успеха :( Может быть, это было неправильное место для добавления ?!
Тима

1
Ваш вопрос только что спросил, как вы можете вызвать метод и запустить его в основном потоке пользовательского интерфейса. Это отвечает на этот вопрос. В вашем конкретном случае ( stackoverflow.com/questions/3670500/… ) AsyncTask и его метод onPostExecute (), кажется, вам следует рассмотреть.
Брайан

12

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

Пожалуйста, следуйте инструкциям Как правильно реализовать BaseAdapter.notifyDataSetChanged () в Android или в новом блоге BaseAdapter.notifyDataSetChanged () .


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

notifyDataSetChanged будет работать для редактирования или изменения набора данных, ваш нулевой указатель из-за чего-то другого, проверьте журналы.
Ариф Надим

7

У меня была та же проблема, и я предпочитаю не заменять весь 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);
        }
    }
}

У меня есть пара других ArrayAdapters в моем коде, и они работали без проблем. Сегодня вечером я решил превратить SimpleCursorAdapter в ArrayAdapter, и он НЕ БУДЕТ РАБОТАТЬ. После нескольких часов борьбы с ним и попытки найти причину, по которой он не работает, я нашел ваш класс AdapterHelper, и СЕЙЧАС ЭТО РАБОТАЕТ! Спасибо!
Proudgeekdad

1
Это легко сделать в функции ... ПОЧЕМУ вы бы создали для нее новый класс?
techiServices

2
В Java функции называются методами. Что бы вы предложили, возможно, этот метод многократного использования в том же классе, что и адаптер массива? Или фрагмент / действие, содержащее представление списка? Так что да, это в классе, где его можно использовать повторно. Если вы хотите, чтобы все было статичным, продолжайте.
Кевин Паркер

1
Хорошая идея. Другой вариант - расширить 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); } }. Теперь просто расширяйте свой класс адаптеров.
Консумьер

Отлично! Большое спасибо @Kevin - это было именно то, что мне нужно!
Киби

3

Я знаю, что это поздний ответ, но я столкнулся с аналогичной проблемой, и мне удалось решить ее, используя 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.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.