web-dev-qa-db-ja.com

RecyclerViewで定義済みのポジションのリサイクルを停止する方法は?

私の問題は、RecyclerView内のビューの1つでビデオストリーミングが発生していることです。

ユーザーがスクロールすると、ビューがリサイクルされ、他のカメラはリサイクルされたビューホルダーで独自のストリーミングを開始します。ストリーミングプロセスの開始には数秒かかるため、これはユーザーインターフェイスにとっては不適切です。

どうやってRecyclerViewに言うことができますか:「ちょっとRecycler、その正確な位置xをリサイクルせずに、その位置 [〜#〜] always [〜# 〜] ランダムなビューホルダーではなく、最初に与えた同じビューホルダー」?

誰か助けてください=(

19
Daniel Oliveira

アダプターのgetItemViewType(int position)メソッドで、各ビデオに一意の値を割り当てます。これにより、同じビデオに対して常に同じViewHolderが返されます。

  • 各ビデオタイプのタイプとして一意の正の数を返します(ここでは、アダプターの位置を一意のキーとして使用しました)
  • ビデオ以外のアイテムには負の数を返します。 (ここでは特別なことはありません。動画アイテムとの競合を避けるため、動画以外のアイテムには負の数を使用しています)

私はあなたがアイデアを得ると思います。乾杯:)

    @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);

         }
    }
14
Darish

リサイクルしたいnotViewHolderviewHolder.setIsRecyclable(false) を実行します。

ViewHolder#setIsRecyclable(boolean) のドキュメント:

このアイテムをリサイクルできるかどうかをリサイクル業者に通知します。リサイクルできないビューは、setIsRecyclable()が後でtrueに設定されるまで、他のアイテムに再利用されません。

これにより、ViewHolderが1つだけ作成されます。

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);
    }
    ...
}
12
azizbekian

RecyclerViewは、画面に一度に表示されないリストが含まれている場合、1つのビューを複数回使用します(リストには、画面を上下にスクロールする必要があると同時に画面に表示されない大量のアイテムが含まれることを意味します)。ユーザーがリストをスクロールすると、オフスクリーンアイテムが再利用され、リサイクルと呼ばれる残りのリストアイテムが表示されます。

アイテムのリサイクルを停止するには、onBindViewHolderメソッドでこのメソッドを呼び出します。

viewHolder.setIsRecyclable(false);

このステートメントは、ビューのリサイクルを停止します。

アイテムのリサイクルを開始するには、onBindViewHolderメソッドでこのメソッドを呼び出します。

viewHolder.setIsRecyclable(true);

これで問題が解決することを願っています。ありがとう

3
Aman Goyal

あなたの問題は、ビューホルダー自体から来ています。ビューホルダーはビューへの参照を保持しますが、アダプターは保持しません。アダプターは、データ収集のみを保持します。そのため、ビューホルダーにフィールドを追加して、ビューホルダーにビューを取り込むために使用したデータ要素の参照を保持します。言い換えると:

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;
    }
}

これで、ビューホルダーは、アダプターのどの要素が使用されているかを認識します。そのため、アダプターでバインディングメソッドをオーバーライドするときに、ホルダーが既にデータと結合しているかどうかを確認できます。また、データにビデオが含まれている場合は、バインディングを回避し、既にロードされたビューを強制的に設定できます。

@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メソッドを定義する必要があります。

2
Fco P.

この答えをrecyclerviewでリサイクルしないアイテムを処理する最良の方法は、あなたの問題を解決します。

アイテムをリサイクルしない

0
Ness Tyagi

その特定の位置にこれを使用してみてください:

 holder.setIsRecyclable(false);

これが役立つことを願っています。

0