【问题标题】:GridView with infinite scroll optimization具有无限滚动优化的 GridView
【发布时间】:2019-04-15 13:13:07
【问题描述】:

我创建了一个简单的应用程序,它从 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 个项目时(如 IOnRepositoryDataReturn 实现中的 clearIfNeeded() 方法所示),屏幕会移动。我不再看到我在删除之前看到的项目。

示例图片。删除images 列表中的第一行(项目 1-2)时的情况。

  • 左图 - 移除前的网格
  • 居中 - 移除后的网格(就目前而言,移除顶部的项目会向上移动所有项目)
  • 正确 - 我希望它的行为方式(移除某处上方的项目不会影响看到的内容)

黑色方块代表GridView。

我想以某种方式调整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 甚至有可能还是我应该寻找其他可能性?

【问题讨论】:

  • 看起来有点复杂。您是否考虑过使用弱引用或软引用?您可以维护您的支持数据数组,并让垃圾收集器担心回收空间。网上有很多参考资料。 Here 是一个。

标签: java android optimization gridview infinite-scroll


【解决方案1】:

当 GridView 中已经有超过 1000 个项目时,我想删除前 300 个项目,这样我就不会遇到内存不足的问题。 网格视图是否有可能,还是我应该寻找其他可能性?

这是我的 2 美分。如果我理解正确,您的担忧似乎是防止 OutOfMemory 异常并提高内存使用率和性能。如果您使用RecyclerView 和GridLayoutManager 实现照片网格,它将减少许多内存问题。您尝试删除屏幕外 300 个项目的方法似乎非常麻烦且容易出错。这是标题为Create a List with RecyclerView的官方文档的摘录:

回收站视图:

RecyclerView 使用布局管理器在屏幕上定位各个项目并确定何时重用用户不再可见的项目视图。为了重用(或回收)视图,布局管理器可能会要求适配器用数据集中的不同元素替换视图的内容。 以这种方式回收视图可以通过避免创建不必要的视图或执行昂贵的 findViewById() 查找来提高性能。

GridLayoutManager:

GridLayoutManager 将项目排列在二维网格中,就像棋盘上的方格一样。将 RecyclerView 与 GridLayoutManager 一起使用可提供类似于旧版 GridView 布局的功能。

您可以在快速搜索中找到许多相关教程,例如:Android GridLayoutManager with RecyclerView

【讨论】:

    【解决方案2】:

    您可以通过以下方式对其进行优化:

    1. 使用 RecycleView + Grid 布局而不是 GridView。 RecycleView 将帮助您的视图平滑滚动。
    2. 为了达到滚动到底部,我不再使用 ScrollListener 以获得更好的性能。我将为您提供另一种选择:

      • 创建回调 公共接口适配器回调 { 无效 onReachLastItem(); }
      • 致电onBindViewHolder: @Override protected void onBindContentViewHolder(RecyclerView.ViewHolder viewHolder, int position) { if (0 != position && position == getItemCount() - 1 && null != mCallback) { mCallback.onReachLastItem(); } }

      • 让您的片段或活动实现 AdapterCallback 以加载更多数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      相关资源
      最近更新 更多