GridView с бесконечной оптимизацией прокрутки - PullRequest
0 голосов
/ 12 ноября 2018

Я создал простое приложение, которое извлекает изображения из Pixabay и затем отображает их в виде GridView с бесконечной прокруткой.

Мой OnScrollListener:

public class BasicOnScrollListener implements AbsListView.OnScrollListener {

private IOnScroll onScroll;

public BasicOnScrollListener(IOnScroll action) {
    this.onScroll = action;
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (firstVisibleItem + visibleItemCount >= totalItemCount - visibleItemCount)
        onScroll.onReachedEnd();
}
}

Код для обработки данных:

private List<Image> images = new ArrayList<>();

....

private void init() {
    this.imageAdapter = new ImageAdapter(this, images);
    this.gridView.setAdapter(imageAdapter);

    populateGridView();
    this.gridView.setOnScrollListener(new BasicOnScrollListener(() -> {
        populateGridView();
    }));
}

private void  populateGridView() {
    if (!isLoading) {
        isLoading = true;
        this.progressBar.setVisibility(View.VISIBLE);
        imagesRepository.getImages(currentPage, PAGE_SIZE, new IOnRepositoryDataReturn<ImagesList>() {
            @Override
            public void onData(ImagesList data) {
                clearIfNeeded();
                images.addAll(data.images);
                imageAdapter.notifyDataSetChanged();
                onFinish();
            }

            @Override
            public void onError(String error) {
                Toast.makeText(getApplicationContext(), error, Toast.LENGTH_LONG).show();
            }

            private void clearIfNeeded() {
                if (images.size() > 1000) {
                    images.subList(0, 300).clear();
                }
            }

            private void onFinish() {
                progressBar.setVisibility(View.INVISIBLE);
                isLoading = false;
                currentPage = currentPage + 1;
            }
        });
    }
}

Все работает хорошо, но я хотел бы оптимизировать это.Когда в GridView уже есть более 1000 элементов, я бы хотел удалить первые 300 элементов, чтобы не было проблем с памятью.

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

Пример изображения.Ситуация при удалении первой строки (пункты 1-2) из ​​списка images.

  • левое изображение - сетка перед удалением
  • center - сетка после удаления (как сейчас, удаление элементов сверху сдвигает все элементы вверх)
  • вправо -как бы я хотел, чтобы он вел себя (удаление предметов где-то вверх не влияет на то, что видно)

Черный квадрат представляет GridView.

enter image description here

Я бы хотел как-то отрегулировать позицию просмотра в GridView, чтобы я все равно видел те же изображения, что и до удаления.

Макет xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/ProgressSpinner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="@+id/GridView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/GridView" />

    <GridView
        android:id="@+id/GridView"
        android:layout_width="match_parent"
        android:layout_height="406dp"
        android:layout_marginBottom="8dp"
        android:numColumns="3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </GridView>

Возможно ли вообще с Grid View или я должен искать какую-то другую возможность?

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Вы можете оптимизировать это следующим образом:

  1. Использование RecycleView + Grid Layout вместо GridView. RecycleView поможет вашему просмотру плавно прокручиваться.
  2. Чтобы достичь прокрутки вниз, я больше не использую ScrollListener для лучшей производительности. Я предоставлю вам другой вариант:

    • Создать обратный звонок открытый интерфейс AdapterCallback { void onReachLastItem (); } * +1010 *
    • Звоните onBindViewHolder: @Override Защищенный void onBindContentViewHolder (RecyclerView.ViewHolder viewHolder, int position) { if (0! = position && position == getItemCount () - 1 && null! = mCallback) { mCallback.onReachLastItem (); } }

    • Сделайте ваш фрагмент или действие реализующим AdapterCallback, чтобы загрузить больше данных.

0 голосов
/ 15 ноября 2018

Когда в GridView уже есть более 1000 элементов, я бы хотел удалить первые 300 элементов, чтобы не было проблем с памятью.Это вообще возможно с Grid View или я должен искать какую-то другую возможность?

Вот мои 2 цента.Если я правильно понимаю, похоже, ваша проблема заключается в предотвращении исключений OutOfMemory и улучшении использования памяти и производительности.Если вы реализуете сетку фотографий, используя RecyclerView и GridLayoutManager, это уменьшит многие ваши проблемы с памятью.Ваш подход к попытке удалить 300 предметов, которые находятся за пределами экрана, кажется довольно громоздким и подверженным ошибкам.Вот выдержка из официального документа под названием Создание списка с помощью RecyclerView :

RecyclerView:

RecyclerView использует менеджер макета для позиционирования отдельных элементов наэкран и определяют, когда следует повторно использовать представления элементов, которые больше не видны пользователю .Чтобы повторно использовать (или перерабатывать) представление, менеджер компоновки может попросить адаптер заменить содержимое представления другим элементом из набора данных. Повторная обработка представлений таким образом повышает производительность, избегая создания ненужных представлений или выполнения дорогостоящих поисков findViewById ().

GridLayoutManager:

GridLayoutManager упорядочивает элементы в двумерной сетке, например, квадраты на шахматной доске.Использование RecyclerView с GridLayoutManager обеспечивает такие же функциональные возможности, как и старый макет GridView.

Для быстрого поиска вы можете найти множество учебных пособий, например: Android GridLayoutManager с RecyclerView

...