其實就是Adapter中可以被覆寫的兩個方法
1、onDetachedFromRecyclerView
看下方法說明
/**
* Called by RecyclerView when it stops observing this Adapter.
*
* @param recyclerView The RecyclerView instance which stopped observing this adapter.
* @see #onAttachedToRecyclerView(RecyclerView)
*/
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
}
在RecyclerView不再觀察這個Adapter時被調(diào)用。
與之對應(yīng)的是onAttachedToRecyclerView:
/**
* Called by RecyclerView when it starts observing this Adapter.
* <p>
* Keep in mind that same adapter may be observed by multiple RecyclerViews.
*
* @param recyclerView The RecyclerView instance which started observing this adapter.
* @see #onDetachedFromRecyclerView(RecyclerView)
*/
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
}
在RecyclerView開始觀察這個Adapter時,被調(diào)用。
通常我們的理解是這樣的:
頁面進(jìn)入時,顯示RecyclerView,調(diào)用onAttachedToRecyclerView,做一些注冊工作;
頁面退出時,銷毀RecyclerView,調(diào)用onDetachedFromRecyclerView,做一些解注冊和其他資源回收的操作。
而實際上,這兩個方法的調(diào)用時機是:
public void setAdapter(Adapter adapter) {
// bail out if layout is frozen
...
setAdapterInternal(adapter, false, true);
...
}
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);//這里onDetachedFromRecyclerView
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
removeAndRecycleViews();
}
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);//這里onAttachedToRecyclerView
}
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
}
可以看到,在調(diào)用setAdapter方法時,新設(shè)置的Adapter會調(diào)用onAttachedToRecyclerView,原有的Adapter會調(diào)用onDetachedFromRecyclerView。
所以如果覆寫了onDetachedFromRecyclerView,為了確保被調(diào)用,需要在頁面退出時,手動調(diào)用setAdapter(null)。
2、onViewDetachedFromWindow
方法說明:
/**
* Called when a view created by this adapter has been detached from its window.
*
* <p>Becoming detached from the window is not necessarily a permanent condition;
* the consumer of an Adapter's views may choose to cache views offscreen while they
* are not visible, attaching and detaching them as appropriate.</p>
*
* @param holder Holder of the view being detached
*/
public void onViewDetachedFromWindow(@NonNull VH holder) {
}
簡言之,就是當(dāng)itemView被從window上detach時調(diào)用。看起來很美好,與之對應(yīng)的方法是:
/**
* Called when a view created by this adapter has been attached to a window.
*
* <p>This can be used as a reasonable signal that the view is about to be seen
* by the user. If the adapter previously freed any resources in
* {@link #onViewDetachedFromWindow(RecyclerView.ViewHolder) onViewDetachedFromWindow}
* those resources should be restored here.</p>
*
* @param holder Holder of the view being attached
*/
public void onViewAttachedToWindow(@NonNull VH holder) {
}
然后我們也如第一個方法般調(diào)用了:
onViewAttachedToWindow中做一些注冊工作;
onViewDetachedFromWindow中做一些解注冊和釋放資源的工作。
在RecyclerView正常滾動時,這兩個方法都會被調(diào)用。然而頁面退出時,onViewDetachedFromWindow并不會被調(diào)用!
追根溯源,會發(fā)現(xiàn)癥結(jié)在LinearLayoutManager中:
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
if (mRecycleChildrenOnDetach) {
removeAndRecycleAllViews(recycler);
recycler.clear();
}
}
默認(rèn)mRecycleChildrenOnDetach=false。我們需要調(diào)用setRecycleChildrenOnDetach(true)才能實現(xiàn)在頁面退出時,依然調(diào)用onViewDetachedFromWindow方法。
整合RecyclerView
可以設(shè)計一個RecyclerView的基類,在基類中做如下處理:
public class BaseRecyclerView extends RecyclerView implements LifecycleObserver {
public BaseRecyclerView(@NonNull Context context) {
super(context);
init(context);
}
public BaseRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public BaseRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
if (context instanceof LifecycleOwner) {
((LifecycleOwner) context).getLifecycle().addObserver(this);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestory() {
/*
確保Adapter#onDetachedFromRecyclerView被調(diào)用
*/
setAdapter(null);
}
@Override
public void setLayoutManager(LayoutManager layoutManager) {
super.setLayoutManager(layoutManager);
if (layoutManager instanceof LinearLayoutManager) {
/*
確保Adapter#onViewDetachedFromWindow被調(diào)用
*/
((LinearLayoutManager) layoutManager).setRecycleChildrenOnDetach(true);
}
}
}