Thursday, 15 November 2018

GridView with infinite scroll optimization

I've created a simple app that fetches images from Pixabay and then displays them in a GridView with infinite scroll.

My 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();
}
}

Code resposible for data handling:

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;
            }
        });
    }
}

Everything works fine but I'd like to optimize that. When there are already more than 1000 items in the GridView I'd like to remove the first 300 items, so I won't run into out of memory problems.

The problem is, when I simply remove the first 300 items from list (as shown in clearIfNeeded() method in IOnRepositoryDataReturn implementation), the screen shifts. I no longer see items that I've seen before removal.

Example image. Situation if first row (items 1-2) from images list is removed.

  • left image - grid before removing
  • center - grid after removing (as it is for now, removing items on top shifts all items up)
  • right - how i'd like it to behave (removing items somewhere up doesnt affect what is seen)

The black square is representing the GridView.

enter image description here

I'd like to somehow adjust the viewing position in GridView, so I'd still see the same images as before removal.

Layout 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>

Is it even possible with Grid View or should i look for some other possibility?



from GridView with infinite scroll optimization

No comments:

Post a Comment