How to make RecyclerView stop processing certain positions?

My problem: I have streaming video happening on one of the views inside the RecyclerView.

When the user scrolls, the view becomes redesigned, and other cameras start their own streaming on this redesigned viewer. This is bad for the user interface since it takes a few seconds for the streaming process.

How can I tell RecyclerView: โ€œHey recyclers, please do not recycle this exact position x and give this position ALWAYS the same viewer that you gave for the first time, instead of random?โ€

Please help me = (

+14
source share
7 answers

In your adapter getItemViewType(int position) assign unique values โ€‹โ€‹for each video, so it will always return the same ViewHolder for the same video as you.

  • returns a unique positive number as a type for each type of video (here I used the adapter position as a unique key)
  • return negative numbers for any items not related to the video. (nothing special here, just to avoid conflicts with the video, we use negative numbers for non-video elements).

I hope you get this idea. greetings :)

  @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); } } 
+13
source

Run viewHolder.setIsRecyclable(false) on the ViewHolder that you want to overload not .

From the docs ViewHolder # setIsRecyclable (boolean) :

Tells the processor whether this item can be recycled. Views that are not recyclable will not be reused for other elements until setIsRecyclable () is set to true.

This will create only one 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); } ... } 
+12
source

Your problem comes from the viewer himself. Viewers have a link to the views, while the adapter does not. The adapter saves only data collection. Thus, add a field to the observer to save a link to the data item that you used to populate the view in the view node. In other words:

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

The viewer now knows which adapter element is using. Therefore, by overriding the binding method in the adapter, you can check whether the holder is already connected to some data, and if the data contains video, you can avoid the binding and force the already loaded view to be installed.

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

Finally, you will have to override the onViewRecycled method in the adapter, so when the view containing the video is processed, you can get the view and put it in another place.

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

remember that this can lead to serious leaks if you do not manage the saved view. In addition, you must define methods for reporting when your data is video, and a properly set equals method.

+2
source

RecyclerView uses one view several times when it contains a list that does not appear on the screen at a time (means that the list contains a large number of elements that do not appear on the screen at the same time, you need to scroll up and down). When the user views the list, splash screen elements are reused to display the remaining list items, which are called recycling.

To stop reusing items, call this method in the onBindViewHolder method:

 viewHolder.setIsRecyclable(false); 

This statement stops reusing views.

To start reusing items, call this method in the onBindViewHolder method:

 viewHolder.setIsRecyclable(true); 

I hope this solves your problem. Thanks

+2
source

Try using this for this particular position:

  holder.setIsRecyclable(false); 

Hope this helps.

0
source

The best way to handle an item not intended for reuse in recycling. See this answer to solve your problem.

Do not recycle goods

0
source

If you use a query, you can use

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

try it.

or Plese post your QueryCode

-eight
source

Source: https://habr.com/ru/post/1264170/


All Articles