RecyclerView.Adapter onViewDetachedFromWindow never called

11,728

I run into the same problem:

As already mentioned you can set the adapter null in the onPause (Activity, Fragment) or onDetachFromWindow (Activity, Fragment)

recyclerview.setAdapter(null)

Then you get viewDetachedFromWindow(...) where you can release your internal states and subscriptions. I would setup your subscriptions in on bind, make sure before every bind call you relase old subscriptions as a view can be recycled.

Another possibility is to inflate a custom view instead of only a layout in your factory. Then you can make the cleanup in the custom view onDetachFromWindow(). You get the onDetachedFromWindow also without setting the adapter to null.

Share:
11,728

Related videos on Youtube

Dokumans
Author by

Dokumans

Updated on June 12, 2022

Comments

  • Dokumans
    Dokumans about 2 years

    What's the way to go if I want my ViewHolders in an RecyclerView to clean up internal state (in this case unregister from an EventBus and clean up Rx-Subscriptions)? I thought that the methods onViewDetachedFromWindow or onViewRecycledin the adapter is the callback where I can cleanup resources (as described in the API), but this method is never called when I change from the Activity with the RecyclerView to another Activity.

    Only onViewAttachedToWindow is called when the activity is entered and i can see my items.

    My adapter looks like this:

    public class Adapter extends RecyclerView.Adapter<MyViewHolder> 
    {
        @Override 
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return factory.getViewholder(parent, viewType, this);
        }
    
        @Override 
        public void onBindViewHolder(MyViewHolder holder, int position) {
            MyItem item = items.get(position);
        holder.bind(item);
        }
    
        @Override
        public void onViewDetachedFromWindow(MyViewHolder holder)
        {
            holder.viewDetached();
            super.onViewDetachedFromWindow(holder);
        }
    
        @Override
        public void onViewAttachedToWindow(MyViewHolder holder)
        {  
            super.onViewAttachedToWindow(holder);
            holder.viewAttached();
        }
    
        @Override
        public void onViewRecycled(MyViewHolder holder)
        {
            super.onViewRecycled(holder);
            holder.viewRecycled();
        }
    
        @Override 
        public int getItemCount() {
            return items.size();
        }
    
        @Override
        public int getItemViewType(int position)
        {
            return items.get(position).getType(this.factory);
        }
    }
    

    The Activity holding the RecyclerView:

    public class MyActivity extends AppCompatActivity
    {
    
       protected void setupView()
       {
            //called in onCreate
    
            recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
            this.adapter = new Adapter(new ItemViewHolderFactory());
       }
    
        @Override
        public void setItems(List<MyItem> items)
        {
            //items are loaded async
            this.adapter.setItems(items);
            this.recyclerView.setAdapter(this.adapter);
            this.recyclerView.scheduleLayoutAnimation();
        }
    }
    

    The ViewHolder looks like this

    public class MyViewHolder extends RecyclerView.ViewHolder
    {
            public void bind(MyItem item)
            {
              //set initial data
            }
    
           public void viewAttached()
           {
            registerToEventBus();
            loadDataAsync(); // here an rx operation is scheduled and a subscription is hold
           }
    
         public void viewDetached()
         {
             unregisterFromEventBus();
             cancelAsyncOperationAndCleanSubscription();
         }
    }
    

    Thanks for any advices.

    EDIT I tried to override onDetachedFromRecyclerView in the adapter, but this method is also not called.

    • Abbas
      Abbas over 7 years
      Are you sure you are setting adapter in your RecyclerView to null by calling mRecyclerView.setAdapter(null)? That should give you onDetachedFromRecyclerView() callback
    • ris8_allo_zen0
      ris8_allo_zen0 almost 7 years
      An alternative is to call setLayoutManager(null); not sure about the side-effect in your case; my RecyclerView is in a TabHost and it works fine.
  • Dokumans
    Dokumans over 5 years
    With today's knowledge I would also prefer the solution with the custom views.