我有一个大约5-6行的ListView,每行都是一个RecycleView,它显示水平片段。卡(例如Netflix,HBO应用)
注意事项:
每个RecycleView都有大约30-50个项目。
每个ViewHolder都有一个“大”图片作为背景(大约300x260dp,具体取决于设备屏幕尺寸,宽度大约是设备屏幕的90%)
通过使用Glide(以下代码)加载图像
我在ListView适配器中为RecycleViews创建了一个缓存(SparseArray),以保持每个RecycleView的状态,否则,每次它离开屏幕时,它都会重新启动到位置0。
这样,只需将每个RecycleView滚动到末尾,即可使其中一些冻结。
尝试了几种解决方法:
审查了MAT,并重构了一些代码,以避免由于静态上下文而导致泄漏
由于图像,MAT显然会显示大量的内存
缩小图像尺寸
隐藏图像
创建ViewHolders的缓存(无效)
Glide下载后,为图片创建一个内存缓存
使ViewHolders setIsRecyclable设置为false
但是,所有这些选项均无效,确保应用不会冻结的唯一方法是避免ListView缓存(如果将View移出屏幕,则会丢失您访问的最后位置)
滑行代码(我在这里尝试了几种选择:避免位图,避免内存缓存,将磁盘策略更新为ALL)
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);
}
}
});
有什么建议/建议吗?
也许还有另一种选择可以保持视图状态而无需缓存?
ListView适配器代码:
@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;
}
}
更新11/04
我终于明白了。
按照建议在适配器上重新使用converView
在RecycleView中包含一个ScrollListener,并将最后一个滚动位置存储在Bean中,以便在重新访问时将其恢复。
这段代码在Adapter中,用于扩展特定行(getView)
// 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();
}
});
最佳答案
这是一个非常广泛和复杂的问题。您的布局很复杂,因此需要花费一些精力才能使其高效。您可以采取的措施来提高性能:
所有RecyclerView
都应尽可能使用视图持有人。如果需要,定义多种视图类型。父级RecyclerView
可能只有一种视图类型,即带有子级RecyclerView
的项。子RecyclerView
也可以通过拥有RecycledViewPool
来共享视图持有者。此处更多信息:https://developer.android.com/reference/android/support/v7/widget/RecyclerView.RecycledViewPool.html
确保所有布局都尽可能平整。您拥有的视图类型越多,它就越重要。
滑行是图像加载的不错选择。确保尽可能使用缓存。下载图像后对其进行缓存,以减少对网络的影响。下载图像时,请使用占位符或进度条。重用视图时,请重置每个ImageView
状态,以避免闪烁。
取消不再需要加载的项目的图像加载。这也应有助于您减少网络活动。
您也可以恢复滚动位置,这里应该没有任何问题。但是,这是一个单独的主题,您可以参考此线程以获取更多详细信息:How to save RecyclerView's scroll position using RecyclerView.State?
并注意MAT,是的。确保您不使用太多资源很重要,在这种情况下,这很容易。
希望对您有所帮助。祝好运!
关于android - 具有水平RecycleView的ListView获得锁定,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49751175/