【问题标题】:I have a Recyclerview and a list with 5000 items but I only want to load 100 items at a time我有一个 Recyclerview 和一个包含 5000 个项目的列表,但我只想一次加载 100 个项目
【发布时间】:2015-02-24 16:37:08
【问题描述】:

我在我的测试应用中实现了Recyclerview。目前,我将大约 5000 项数据提取到模型中,并使用此列表加载我的视图。一切都很棒,性能也很好,但我不想加载所有 5000 个项目。我更喜欢加载 100 个项目,一旦用户到达底部,加载下一个 100 并使其成为一个不断增长的列表。

我可以针对Recyclerview 实施onScrollListener 来检测我何时到达终点,但我的问题(就像这听起来一样简单)是,告诉Recyclerview 的最佳方法是什么?在我说之前只加载 100 个?

我的适配器:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<ImageFeed> mFeedList;

    public MyAdapter(List<ImageFeed> feedList) {
        this.mFeedList = feedList;
    }

    public void setFeedList(List<ImageFeed> feedList) {
        mFeedList = feedList;
    }

    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup vGroup, int i) {
        View v = LayoutInflater.from(vGroup.getContext()).inflate(R.layout.recycler_list, vGroup, false);
        return new MyAdapter.ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, int i) {
        String mTitle = mFeedList.get(i).getTitle();

        ...//Do other stuff
    }

    @Override
    public int getItemCount() {
        return mFeedList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        protected ImageView mImageView;
        protected TextView mTitle;
        protected ProgressBar mLoader;
        private int mItemId;

        public ViewHolder(View itemView) {
            super(itemView);
            this.mImageView = (ImageView) itemView.findViewById(R.id.imgItem);
            this.mTitle = (TextView) itemView.findViewById(R.id.txtTitle);
            this.mLoader = (ProgressBar) itemView.findViewById(R.id.mLoaderProgress);

            this.mImageView.setOnClickListener(this);
            itemView.setOnClickListener(this);
        }

        public void setItem(int item) {
            this.mItemId = item;
        }

        @Override
        public void onClick(View v) {
            if (v instanceof ImageView) {
                Toast.makeText(v.getContext(), "Image view clicked: " + this.mItemId, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(v.getContext(), this.mItemId + " ", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

想出这个场景我会认为传递一个较小的列表是可能的,但感觉并不完全正确。

【问题讨论】:

  • 是的,其实是一种常见的pattern。也许你可以在远离底部的 x 个元素时开始预加载它
  • 我可能误解了这个问题,但这似乎并不特定于 RecyclerView。如果您已经完成了装载 5,000 件物品的工作,那么您已经完成了繁重的工作。如果没有,我认为您通过实现 onScrollListener 并在用户到达底部时简单地加载后续数据页面,从而走上正轨。
  • 这是一个常见问题,但我不知道常见/简单的解决方案。标准适配器概念没有包含任何内容来告诉您需要或当前显示的支持模型的哪一部分。它只是为了“适应”从 加载的 数据到显示的项目。你可以解决例如通过滚动侦听器或显示时触发加载的特殊项目(显示“正在加载..”的列表项目)实现自动加载,通过按钮/滑动/..手动分页,甚至通过在异步加载实际项目时显示虚拟项目(图像加载器会做那种事情)。
  • 好吧,从它的声音来看,最好的方法是不进行初始 5000 加载。更好的方法是在较小的部分中执行此操作,并让滚动侦听器在接近底部时执行额外的获取请求。好吧,这听起来像是我的想法之一。我会解决这个问题并回来更新。伙计们干杯!

标签: android listview android-recyclerview


【解决方案1】:

好吧,毕竟这并不是特别困难 - 我认为我的主要问题是过度考虑场景......

所以我要做的第一件事是获取适当的数据(在本例中是通过 JSON)并将其存储在 JSON 数组中以供以后操作 - 目前我仍在获取完整的数据集(即 5000),但这很容易改变。

这是通过带有不确定进度条的 AsyncTask 完成的。完成后,我只将 JSON 解析为 20 个元素并将其加载到适配器中。

一旦完成,我就有了我的 Recyclerview.onScrollListener....

mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                mOnScreenItems = mRecyclerView.getChildCount();
                mTotalItemsInList = llm.getItemCount();
                mFirstVisibleItem = llm.findFirstVisibleItemPosition();

                if (mLoadingItems) {
                    if (mTotalItemsInList > mPreviousTotal) {
                        mLoadingItems = false;
                        mPreviousTotal = mTotalItemsInList;
                    }
                }

                if (!mLoadingItems && (mTotalItemsInList - mOnScreenItems) <= (mFirstVisibleItem + mVisibleThreshold)) {
                    new AsyncLoadTask().execute();
                    mLoadingItems = true;
                }
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

        });

当它接近尾声或到达底部时,将启动一个新的 AsynTask 以将其他项目加载到列表中。 onPostExecute() 然后通过其mMyAdapter.notifyDataSetChanged(); 方法更新适配器,从而实现非常平滑的更新。有很多清理工作要做,但基本都在那里。

谢谢大佬指点!

【讨论】:

  • 不错的一个家伙。但是,我不得不额外做一件事。而不是使用 mMyAdapter.notifyDataSetChanged();我使用了 mMyAdapter.notifyItemInserted(position);这样适配器就不会为已加载的项目占用内存。
猜你喜欢
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多