RecyclerView.Adapter onViewDetachedFromWindow never called
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.
Related videos on Youtube
Dokumans
Updated on June 12, 2022Comments
-
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
oronViewRecycled
in 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 theActivity
with theRecyclerView
to anotherActivity
.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 theRecyclerView
: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 over 7 yearsAre you sure you are setting adapter in your
RecyclerView
to null by calling mRecyclerView.setAdapter(null)? That should give youonDetachedFromRecyclerView()
callback -
ris8_allo_zen0 almost 7 yearsAn 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 over 5 yearsWith today's knowledge I would also prefer the solution with the custom views.