Статьи

Android ListView: бесконечный адаптер

Этот пост объясняет, как создать бесконечный адаптер для ListView. Бесконечный адаптер — это адаптер, который загружает больше данных, когда пользователь достигает конца ListView. Этот вид адаптера полезен, когда имеется большое количество элементов, и мы не хотим показывать их все, чтобы избежать длительного времени загрузки. Для достижения этой цели мы создадим:

  • настраиваемый просмотр списка
  • слушатель
  • пользовательский адаптер

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

android_endless_adapter [5]

Пользовательский бесконечный ListView компонент

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

01
02
03
04
05
06
07
08
09
10
11
12
public class EndlessListView extends ListView implements OnScrollListener {
..
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        ...
        }
 
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {}
 
}

В строке 1 мы расширяем ListView и реализуем OnScrollListener, чтобы получать уведомления, когда пользователь прокручивает время в ListView. В строке 4 мы переопределяем метод onScroll, вызываемый во время прокрутки. Когда мы достигаем конца ListView, мы должны показать представление, которое информирует пользователя, чтобы он дождался загрузки всех данных. Мы можем использовать «трюк», чтобы показать индикатор ожидания, мы можем использовать нижний колонтитул ListView. Мы можем добавлять и удалять его по мере необходимости. Чтобы сделать наш компонент настраиваемым, мы можем просто установить представление для использования нижнего колонтитула:

1
2
3
4
5
6
public void setLoadingView(int resId) {
    LayoutInflater inflater = (LayoutInflater) super.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    footer = (View) inflater.inflate(resId, null);
    this.addFooterView(footer);
 
}

Давайте сосредоточимся на методе onScroll. Здесь мы должны проверить, больше ли firstVisibleElement plus itemCounts (количество элементов, отображаемых внутри ListView), чем общее количество элементов. Если это условие проверено, мы можем запустить событие, чтобы загрузить больше данных:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
 
    if (getAdapter() == null)
        return ;
 
    if (getAdapter().getCount() == 0)
        return ;
 
    int l = visibleItemCount + firstVisibleItem;
    if (l >= totalItemCount && !isLoading) {
        // It is time to add new data. We call the listener
        this.addFooterView(footer);
        isLoading = true;
        listener.loadData();
    }
}

В строке 12 мы просто добавляем нижний колонтитул, чтобы сообщить пользователю, что загружаем больше данных, затем в строке 13 мы устанавливаем истинный логический атрибут, чтобы он не вызывал событие снова, пока мы все еще загружаем данные, а затем мы вызываем прослушиватель.

Как видите, слушатель очень прост:

1
2
3
public static interface EndlessListener {
    public void loadData() ;
}

Еще одна вещь, когда процесс загрузки данных закончен, наш пользовательский ListView должен быть проинформирован, чтобы мы могли обновить элементы и удалить нижний колонтитул:

1
2
3
4
5
6
public void addNewData(List<String> data) {
    this.removeFooterView(footer);
    adapter.addAll(data);
    adapter.notifyDataSetChanged();
    isLoading = false;
}

В строке 4 мы вызываем notifyDataSetChanged, чтобы сообщить адаптеру об изменении набора данных.

Тестирование пользовательского компонента

Чтобы протестировать пользовательский компонент, мы можем создать простой макет, включая наш собственный ListView:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
 
    <com.survivingwithandroid.endlessadapter.EndlessListView android:id="@+id/el"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"  />
 
</RelativeLayout>

и нам нужна основная деятельность, чтобы:

01
02
03
04
05
06
07
08
09
10
11
12
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    lv = (EndlessListView) findViewById(R.id.el);
    EndlessAdapter adp = new EndlessAdapter(this, createItems(mult), R.layout.row_layout);
    lv.setLoadingView(R.layout.loading_layout);
    lv.setAdapter(adp);
    lv.setListener(this);
 
}

В строке 7 мы устанавливаем представление нижнего колонтитула, затем в строке адаптер и в конце мы устанавливаем нашу активность в качестве прослушивателя для нашего пользовательского ListView. Чтобы эмулировать данные загрузки через Интернет, мы можем просто создать AsyncTask и заставить наш поток спать в течение нескольких секунд. Обратите внимание, что в onPostExecute:

1
2
3
4
5
@Override
protected void onPostExecute(List<String> result) {           
    super.onPostExecute(result);
    lv.addNewData(result);
}

В строке 4 мы добавляем новые загруженные данные.

Исходный код доступен @ github .

Ссылка: Android ListView: бесконечный адаптер от нашего партнера JCG Франческо Аццолы в блоге Surviving w / Android .