其实就是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时被调用。
与之对应的是onAttachedToRecyclerView
:
/**
* Called by RecyclerView when it starts observing this Adapter.
*
* 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时,被调用。
通常我们的理解是这样的:
页面进入时,显示RecyclerView,调用onAttachedToRecyclerView
,做一些注册工作;
页面退出时,销毁RecyclerView,调用onDetachedFromRecyclerView
,做一些解注册和其他资源回收的操作。
而实际上,这两个方法的调用时机是:
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;
}
可以看到,在调用setAdapter方法时,新设置的Adapter会调用onAttachedToRecyclerView
,原有的Adapter会调用onDetachedFromRecyclerView
。
所以如果覆写了onDetachedFromRecyclerView
,为了确保被调用,需要在页面退出时,手动调用setAdapter(null)
。
2、onViewDetachedFromWindow
方法说明:
/**
* Called when a view created by this adapter has been detached from its window.
*
* 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.
*
* @param holder Holder of the view being detached
*/
public void onViewDetachedFromWindow(@NonNull VH holder) {
}
简言之,就是当itemView被从window上detach时调用。看起来很美好,与之对应的方法是:
/**
* Called when a view created by this adapter has been attached to a window.
*
* 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.
*
* @param holder Holder of the view being attached
*/
public void onViewAttachedToWindow(@NonNull VH holder) {
}
然后我们也如第一个方法般调用了:
onViewAttachedToWindow
中做一些注册工作;
onViewDetachedFromWindow
中做一些解注册和释放资源的工作。
在RecyclerView正常滚动时,这两个方法都会被调用。然而页面退出时,onViewDetachedFromWindow
并不会被调用!
追根溯源,会发现症结在LinearLayoutManager中:
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
if (mRecycleChildrenOnDetach) {
removeAndRecycleAllViews(recycler);
recycler.clear();
}
}
默认mRecycleChildrenOnDetach=false
。我们需要调用setRecycleChildrenOnDetach(true)
才能实现在页面退出时,依然调用onViewDetachedFromWindow
方法。
整合RecyclerView
可以设计一个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被调用
*/
setAdapter(null);
}
@Override
public void setLayoutManager(LayoutManager layoutManager) {
super.setLayoutManager(layoutManager);
if (layoutManager instanceof LinearLayoutManager) {
/*
确保Adapter#onViewDetachedFromWindow被调用
*/
((LinearLayoutManager) layoutManager).setRecycleChildrenOnDetach(true);
}
}
}