Android 具有水平循环的ListView查看获取锁

Android 具有水平循环的ListView查看获取锁,android,listview,android-recyclerview,android-glide,Android,Listview,Android Recyclerview,Android Glide,我有一个大约5-6行的ListView,每行都是一个显示水平片段的RecycleView。卡片(例如Netflix、HBO应用程序) 考虑事项: 每个RecycleView大约有30-50个项目 每个ViewHolder都有一个“大”图片作为背景(大约300x260dp,取决于设备屏幕大小,宽度约为设备屏幕的90%) 使用Glide加载图像(代码如下) 我在ListView适配器中为RecycleView创建了一个缓存(SparseArray),以保持每个RecycleView的状态,否则每

我有一个大约5-6行的ListView,每行都是一个显示水平片段的RecycleView。卡片(例如Netflix、HBO应用程序)

考虑事项:

  • 每个RecycleView大约有30-50个项目
  • 每个ViewHolder都有一个“大”图片作为背景(大约300x260dp,取决于设备屏幕大小,宽度约为设备屏幕的90%)
  • 使用Glide加载图像(代码如下)
我在ListView适配器中为RecycleView创建了一个缓存(SparseArray),以保持每个RecycleView的状态,否则每次它离开屏幕时都会重新启动到位置0

通过这样做,只需将每一个RecycleView滚动到最后,就可以使其中一些内容冻结

尝试了几种解决方法:

  • 审查了MAT并重构了一些代码,以避免由于静态上下文而导致的泄漏
  • MAT显然因为图像而显示了大量内存
  • 缩小了图像的大小
  • 隐藏图像
  • 创建ViewHolder的缓存(不起作用)
  • 在Glide下载后为图像创建内存缓存
  • 使ViewHolders设置可循环为false
但是,这些选项都不起作用,保证应用程序不被冻结的唯一方法是避免ListView缓存(如果将视图移出屏幕,则会丢失上次访问的位置)

Glide代码(我在这里尝试了几个选项:避免位图,避免内存缓存,将磁盘策略更新为ALL)


这是一个非常广泛和复杂的问题。您的布局很复杂,因此需要一些努力才能提高效率。您可以采取哪些措施来提高性能:

  • 所有
    RecyclerView
    s应尽可能使用视图保持架。如果需要,定义多个视图类型。父级
    RecyclerView
    可能只有一种视图类型,即具有子级
    RecyclerView
    的项。子
    RecyclerView
    s也可以通过拥有
    recycleredviewpool
    来共享视图持有者。更多信息请点击此处:
  • 确保所有布局尽可能平坦。视图类型越多,这一点就越重要
  • Glide是一个很好的图像加载选择。确保尽可能使用缓存。下载图像后缓存图像,以减少对网络的影响。下载图像时使用占位符或进度条。重新使用视图时,重置每个
    ImageView
    状态,以避免闪烁
  • 取消加载不再需要加载的项目的图像。这也有助于减少网络活动
  • 您也可以恢复滚动位置,这里应该没有任何问题。不过,这是一个单独的主题,您可以参考此线程了解更多详细信息:
  • 注意垫子,是的。重要的是要确保不要使用太多的资源,这在这种情况下非常容易

我希望这有帮助。祝你好运

请将适配器的代码添加到ListView adapter code@CaoMinhVu中,感谢您查看。有两件事我觉得非常可疑:1)您根本没有使用
convertView
,即您从不重用适配器中的视图,也没有利用会降低性能的回收逻辑。在这种情况下,您必须为每个项目膨胀视图,这是一项代价高昂的操作。2) 关于java命名约定,我假设
VenueFilterFragment
是一个类名,因此
loadFragment
是一个奇怪的静态方法。。这样做的目的是什么?我正在为ListView中的不同类型的单元格使用片段,这些片段可以用于应用程序的其他部分。静态方法仅用于在给定视图上设置内容。(但现在作为片段执行,因为我失去了所有片段生命周期)。关于第1点,你是对的,现在研究它。这听起来确实很奇怪。如果要为给定的片段设置内容,它应该是片段对象上的非静态方法。静态方法是在片段类上设置“所谓”状态,这意味着它是某种共享数据。我看到您在每次调用
getView
时都向这个共享状态传递一个filter对象,这对我来说真的没有多大意义。我想不出哪种情况是正确的。请重新考虑这个逻辑,你很可能不想在那里打静态电话。谢谢!我刚刚添加了我的ListView适配器代码,可能是因为我加载包含RecycleView的片段的方式——您在上一个链接中建议的方法不起作用(因此,onSaveState…未被调用)——将查看其余部分,或者可能会找到另一种管理片段生命周期的方法。最好的!
Glide.with(context).load(url)
                .asBitmap()
                .skipMemoryCache(true)
                .thumbnail(0.5f)
                .centerCrop()
                .error(placeHolderId)
                .diskCacheStrategy(DiskCacheStrategy.RESULT)
                //.priority(Priority.NORMAL)
                .dontAnimate()
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
                        if (bitmap != null) {
                            imgView.setImageBitmap(bitmap);
                            //cache.put(url, bitmap);
                        } else {
                            imgView.setBackground(null);
                        }
                    }
                });
@Override
public View getView(int position, View convertView, ViewGroup parent) {
            case TYPE_VENUE_FILTER: {
            View v;
            // Create a new view into the list.
            LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if (inflater != null) {
                v = inflater.inflate(R.layout.fragment_venue_filter, parent, false);
            }

            // We need to get the exact filter to be displayed
            int index = position - FIRST_VENUE_FILTER_ROW;
            if (index < this.filters.size()) {
                VenueFilter filter = this.filters.get(index);

                // Recalculate the distance order
                filter.sortVenuesForLocation(this.lastLocation);

                // Set data into the view.
                VenueFilterFragment.loadFragment(this.context, v, filter, this.fm);
            }

            return v;
        }
}
    // We should reset or recover the scroll state
    LinearLayoutManager llm = (LinearLayoutManager) filterContent.getLayoutManager();
    if (filter.offset > 0) {
        if (llm != null) llm.scrollToPosition(filter.offset + 1);
    } else {
        if (llm != null) llm.scrollToPosition(0);
    }

    // We need to clear every time. Because we are reusing the view
    recycleView.clearOnScrollListeners();

    // We need to create a new specific scroll listener
    recycleView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            // Keeping the offset for a future load
            LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager();
            if (llm != null) filter.offset = llm.findFirstVisibleItemPosition();
        }
    });