如何让 RecyclerView 停止回收定义的位置?

How to make RecyclerView stops recycling defined positions?

我的问题是:我在 RecyclerView 中的一个视图上发生了视频流。

当用户滚动时,视图将被回收,并且其他相机会在该回收的取景器上开始自己的流式传输。这对用户界面不利,因为流式传输过程需要几秒钟才能开始。

如何对 RecyclerView 说:"Hey Recycler, please, do not recycle that exact position x and give that position ALWAYS the same viewholder you gave it the first time, instead of random one"?

请有人帮助我=(

如果你正在使用查询,你可以使用

query.limit(//no of items you want to show in your RecyclerView)  

试一试。

或请post您的查询代码

ViewHolder 上执行 viewHolder.setIsRecyclable(false) 您希望 被回收。

来自docs of ViewHolder#setIsRecyclable(boolean)

Informs the recycler whether this item can be recycled. Views which are not recyclable will not be reused for other items until setIsRecyclable() is later set to true.

这将导致只创建一个 ViewHolder

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    ...
    @Override
    public void onViewAttachedToWindow(final RecyclerView.ViewHolder holder) {
        if (holder instanceof VideoViewHolder) {
            holder.setIsRecyclable(false);
        }
        super.onViewAttachedToWindow(holder);
    }

    @Override
    public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder) {
        if (holder instanceof VideoViewHolder){
            holder.setIsRecyclable(true);
        }
        super.onViewDetachedFromWindow(holder);
    }
    ...
}

您的问题来自取景器本身。 Viewholders 保留对视图的引用,而适配器则不。适配器仅保留数据集合。因此,向 viewholder 添加一个字段以保留对用于在 viewholder 中填充视图的数据元素的引用。也就是说:

public class SomeViewHolder extends RecyclerView.ViewHolder{

    private View view;
    private Data data;

    public SomeViewHolder(View itemView) {
        super(itemView);
        view = itemView;
    }

    public void bindData(Data data){
        view.setData(data);
        this.data = data;
    }

    public void setData(Data data){
       this.data = data;
    }


    public Data getData(){
        return data;
    }

    public View getView(){
        return view;
    }
}

现在,viewholder 知道适配器的哪个元素正在使用。因此,在adapter中覆盖绑定方法时,可以检查holder是否已经绑定了一些数据,如果数据中包含video,则可以避免绑定并强制设置一个已经加载的视图。

@Override
public void onBindViewHolder(SomeViewHolder holder, int position) {

    //videoViewData is a data field you have to put into the adapter.
    //videoView is a view field you have to put into the adapter.

    if(adapterData.get(position).equals(videoViewData)){
        holder.setView(videoView);
        holder.setData(adapterData.get(position));
    }else{
        holder.bindData(adapterData.get(position));
        if(adapterData.get(position).isVideo()){
            videoViewData = adapterData.get(position);
            videoView = holder.getView(); 
        }
    }

}

最后,您必须覆盖适配器中的 onViewRecycled 方法,因此,当包含视频的视图被回收时,您可以获取该视图并将其放在其他地方。

public void onViewRecycled(SomeViewHolder holder){
    if(holder.getData().isVideo()){
        videoViewData = holder.getData().
        videoView = holder.getView();
        videoView.pauseVideo();
    }
}

请记住,如果您不管理存储的视图,这可能会导致一些严重的泄漏。此外,您必须定义用于判断数据何时为视频的方法,以及正确定义的 equals 方法。

尝试将此用于特定位置:

 holder.setIsRecyclable(false);

希望这可能有所帮助。

在您的 getItemViewType(int position) 适配器方法中,为每个视频分配唯一值,因此它将始终 return 相同视频的相同 ViewHolder,如您所愿。

  • return 唯一正数作为每种视频类型的类型(这里我使用适配器位置作为唯一键)
  • return 任何非视频项目的负数。 (这里没有什么特别的,只是为了避免与视频项目冲突,我们对非视频项目使用负数)

我希望你明白了。干杯:)

    @Override
    public int getItemViewType(int position) {
        // Just as an example, return 0 or 2 depending on position
        // Note that unlike in ListView adapters, types don't have to be   contiguous
        if(dataList.get(position).isVideo()){
            return position;

        }else{
            return -1;//indicates general type, if you have more types other than video, you can use -1,-2,-3 and so on.
        }
    }

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case -1:  View view1 = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.general_item, parent, false);
                     return new GeneralViewHolder(view1);
             default:View view2 = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.video_item, parent, false);
                     return new VideoViewHolder(view2);

         }
    }

RecyclerView 多次使用一个视图,当它包含一次没有显示在屏幕上的列表时(意味着一个列表包含大量没有同时显示在屏幕上的项目,你需要向上滚动和向下)。当用户滚动列表时,屏幕外的项目将被重新使用以显示剩余的列表项目,这称为回收。

要停止回收项目,请在您的 onBindViewHolder 方法中调用此方法:

viewHolder.setIsRecyclable(false);

此声明停止回收视图。

要开始回收项目,请在您的 onBindViewHolder 方法中调用此方法:

viewHolder.setIsRecyclable(true);

希望这能解决您的问题。 谢谢

在 recyclerview 中处理不回收物品的最佳方法此答案将解决您的问题。