如何阻止RecyclerView中Header的WebView被回收以保留视频播放状态?
嘿,这个问题我之前也遇到过,RecyclerView的Header被回收确实挺头疼的,尤其是里面有播放视频的WebView,一滚出视野就断了。我给你几个可行的解决方案,你可以根据自己的需求选:
方案1:把Header从RecyclerView里独立出来(最简单直接)
既然RecyclerView的Item必然会被回收,那咱们干脆不让Header成为RecyclerView的Item。把它作为RecyclerView的兄弟View放在布局里,这样它就完全不受RecyclerView的回收机制影响了。
比如你的布局可以改成这样:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 独立的Header,完全脱离RecyclerView --> <include layout="@layout/layout_discover_header" /> <!-- RecyclerView只承载普通视频列表项 --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/listVideos" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
然后你的Adapter里就可以删掉VIEW_TYPE_HEADER相关的逻辑了,只处理普通的视频Item就行。如果需要滚动时隐藏Header,还可以监听RecyclerView的滚动事件来控制Header的显示/隐藏,灵活性很高。
方案2:自定义LayoutManager,强制保留Header
如果你必须让Header作为RecyclerView的第一个Item,那可以重写LayoutManager的回收逻辑,告诉它永远不要回收Header位置的View。
写一个自定义的LinearLayoutManager:
public class KeepHeaderLayoutManager extends LinearLayoutManager { // 假设Header在第0位 private static final int HEADER_POSITION = 0; public KeepHeaderLayoutManager(Context context) { super(context); } @Override public boolean shouldRecycleView(int position) { // 对Header位置的View,返回false表示不回收 return position != HEADER_POSITION; } }
然后给RecyclerView设置这个LayoutManager:
listVideos.setLayoutManager(new KeepHeaderLayoutManager(context));
这样哪怕Header滚出了屏幕,RecyclerView也不会回收它,WebView和视频播放状态就能保留了。
方案3:修正setIsRecyclable(false)的调用时机
你之前试过holder.setIsRecyclable(false)但没生效,大概率是调用时机不对。这个方法应该在创建HeaderHolder的时候就设置,而不是在onBindViewHolder里——因为onBindViewHolder会被多次调用,可能覆盖之前的设置,或者Holder已经进入回收流程了。
修改你的onCreateViewHolder:
@Override public DiscoverPlayerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_HEADER) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.layout_discover_header, parent, false); HeaderHolder holder = new HeaderHolder(itemView); // 在这里设置!创建Holder时就标记为不可回收 holder.setIsRecyclable(false); return holder; }else { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item_discover_video, parent, false); return new ItemHolder(itemView); } }
同时记得去掉你之前设置的listVideos.getRecycledViewPool().setMaxRecycledViews(0, 0);,这个设置会干扰Holder的回收标记,反而可能导致问题。
这三个方案里,我最推荐方案1,实现起来最简单,也最不容易踩坑;如果必须让Header作为列表的一部分,方案2和3都能解决问题,你可以根据自己的场景选。
内容的提问来源于stack exchange,提问作者KunalK

