ListViews - как использовать функцию ArrayAdapter.addAll () перед API 11?

17

Я пытаюсь обновить ListView с совершенно новым ArrayList. Для API 11 он отлично работает с использованием метода addAll (...), но он недоступен для более ранних API. Я не могу понять, как обновить весь список, подобный этому, для более старых версий.

ArrayAdapter<String> textList = new ArrayAdapter<String>(listener, R.layout.list_item, stringList);
listener.setListAdapter(textList);

Затем позже ...

textList.clear();
textList.addAll(stringList); <--- works fine for Android 3.0 (API Level 11) and beyond, but not before. 

Как вы это делали, прежде чем addAll () был введен в API 11? Спасибо.

    
задан mattboy 13.03.2012 в 02:29
источник

8 ответов

11

Простейший способ избежать использования ArrayAdapter.addAll () и ArrayAdapter.add () в цикле, как предположил идиотиггер в своем ответе.

Если вы настаиваете на использовании ArrayAdapter.addAll (), короткий ответ - DIY. Проверьте источник android.widget.ArrayAdapter здесь , фактическая реализация намного проще, чем вы думали. есть много альтернатив для достижения этого, например:

  • Вариант 1: Внедрите свой собственный массив ArrayAdapter android.widget.BaseAdapter, вы получаете полный контроль над частным экземпляром переменной и методом и может определить, какой метод вы хотите в своем собственной реализации. есть много учебников в Интернете, рассказывающих, как для создания пользовательского адаптера, например здесь и here .
  • Вариант 2: Внедрите свой собственный массив ArrayAdapter android.widget.ArrayAdapter, затем добавьте требуемый общедоступный метод addAll () в вашу собственную реализацию ArrayAdapter, у вас нет видимость на частном члене в android.widget.ArrayAdapter поэтому нужна используйте существующий общедоступный API ArrayAdapter.add (), чтобы добавить каждый элемент внутри цикла.

Вариант 1 является предпочтительным и используется очень часто, особенно в ситуации, когда вам нужно визуализировать более сложные пользовательские элементы пользовательского интерфейса в вашем ListView.

    
ответ дан yorkw 13.03.2012 в 03:48
источник
  • не было бы излишним реализовать собственную версию ArrayAdapter из BaseAdapter, чтобы иметь метод addAll? Построить его из ArrayAdapter должно быть достаточно. –  josephus 13.03.2012 в 04:19
  • Да, по-прежнему стоит проверить источник, чтобы понять, как Adapter реализуется в целом. –  yorkw 13.03.2012 в 04:24
  • это несколько несвязано, но посмотрите этот пост, если вы используете Eclipse для разработки приложений для Android: helloandroid.com/content/... –  josephus 13.03.2012 в 04:39
  • Спасибо, я полагаю, это ответ. Разве можно каким-то образом использовать метод notifyDataSetChanged (), например, предложенный Джозефус? Как работает этот метод? –  mattboy 13.03.2012 в 08:22
  • @mattboy, notifyDataSetChanged () берется за базовую структуру (определенную в android.widget.BaseAdapter), каждый класс extends должен обладать этой функцией, например встроенным API android.widget.ArrayAdapter. –  yorkw 13.03.2012 в 09:25
19

Вот полный блок кода, который использует собственный addAll () для Android-устройств с SDK_INT & gt; = 11 и использует обходной путь для устройств с уровнем API менее 11.

@TargetApi(11)
public void setData(List<String> data) {
    clear();
    if (data != null) {
        //If the platform supports it, use addAll, otherwise add in loop
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            addAll(data);
        } else {
            for(String item: data) {
                add(item);
            }
        }
    }
}

Аннотации @TargetApi(11) используются с ADT 17 для подавления предупреждений Lint, когда у вас есть <uses-sdk android:minSdkVersion="X"/> в AndroidManifest.xml, где X меньше 11. См. Ссылка для получения дополнительной информации.

    
ответ дан Sean Barbeau 07.09.2012 в 16:48
источник
  • хороший ответ, но позвольте мне поделиться с вами своим опытом: если вы используете метод «add» с более чем x элементами (я уже установил его на 100), так как после каждого метода «добавить» будет вызов «notifydatasetchanged», произойдет сбой! –  Analizer 10.09.2014 в 14:11
  • @ Анализатор с таким количеством записей, возможно, вам лучше использовать CursorAdapter? См. Stackoverflow.com/questions/21130162/.... –  Sean Barbeau 10.09.2014 в 16:28
  • Это неплохая идея, но я не использую базу данных, записи удаляются из ответа JSON с сервера. –  Analizer 11.09.2014 в 10:38
  • Я добавил setNotifyOnChange (false); / notifyDataSetChanged (); Пара: если у вас есть сотни предметов (~ 800 в моем случае), это значительно улучшает производительность (1500 мс против <1 мс), поскольку это предотвращает вызов notifyDataSetChanged () после каждого добавления (). –  Nikita Bosik 25.01.2015 в 02:19
4

Я сочетал ответы barbeau и Villarey с тем, что, по моему мнению, является хорошим решением:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setData(List<String> data) {
    clear();
    if (data != null) {
        addAll(data);
    }
}


@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void addAll(String... items) {
    //If the platform supports it, use addAll, otherwise add in loop
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        super.addAll(items);
    }else{
        for(String item: items){
            super.add(item);
        }
    }
}
    
ответ дан elBradford 13.12.2012 в 01:43
источник
3

Я построил код других людей онлайн, и я создал это. Просто используйте этот класс везде, где это необходимо, вместо класса ArrayAdapter .

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.widget.ArrayAdapter;

import java.util.Collection;
import java.util.List;

public class ArrayAdapterCompat<T> extends ArrayAdapter<T> {
    public ArrayAdapterCompat(Context context, int resource, List<T> entries) {
        super(context, resource, entries);
    }

    /**
     * Add all elements in the collection to the end of the adapter.
     * @param list to add all elements
     */
    @SuppressLint("NewApi")
    public void addAll(Collection<? extends T> list) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            super.addAll(list);
        } else {
            for (T element : list) {
                super.add(element);
            }
        }
    }

    /**
     * Add all elements in the array to the end of the adapter.
     * @param array to add all elements
     */
    @SuppressLint("NewApi")
    public void addAll(T... array) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            super.addAll(array);
        } else {
            for (T element : array) {
                super.add(element);
            }
        }
    }
}
    
ответ дан KVISH 15.12.2013 в 07:04
источник
1

, используя метод textList.add , цикл в списке строк и один за другим, добавленный в текстовый список.

    
ответ дан idiottiger 13.03.2012 в 02:48
источник
1

Вы можете расширить ArrayAdapter на пользовательский класс и реализовать свой собственный метод addAll. Было бы проще использовать ArrayList вместо массива String, поэтому вы можете добавлять данные без восстановления всего набора данных.

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

    
ответ дан josephus 13.03.2012 в 04:13
источник
  • Итак, вы имеете в виду, что в этом случае я просто изменил бы значения переменной stringList, а затем вызовет textList.notifyDataSetChanged () ;? Я на самом деле пробовал это, но это не сработало. Я что-то упускаю? Я думаю, что я где-то читал, что этот метод работает, только если вы отредактировали адаптер .add или .clear или .remove? –  mattboy 13.03.2012 в 08:06
0

Я наткнулся на эту тему поздно, но для меня было легко реализовать следующее решение:

public class CustomAdapter extends ArrayAdapter<String>...

public void setData(ArrayList<String> items) {
    clear();
    setNotifyOnChange(false);
    if (items != null) {
        for (String item : items)
            add(item);
    }
    notifyDataSetChanged();
}
    
ответ дан elprl 06.09.2012 в 16:08
источник
0

просто вам нужно просто iteration над collection с if statement для version

        //mForecastAdapter.clear();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mForecastAdapter.addAll(weekForecast);
        }else {
            for (String s : strings) {
                mForecastAdapter.add(s);
            }
        }
    
ответ дан Basheer AL-MOMANI 07.01.2016 в 22:03
источник