RecyclerView不会在方向更改时从适配器中注销自身 [英] RecyclerView doesn't unregister itself from the adapter on orientation change
问题描述
我曾经在我的android应用程序中使用ListView
,最近我切换到了RecyclerView
,发现它在方向改变时引入了一些内存泄漏.经过进一步调查,原因显而易见了
I used to use ListView
in my android application and I recently switched to RecyclerView
and observed that it introduced some memory leaks on orientation change. On further investigation, the reason became apparent
设置
一个单独的activity
承载一个fragment
,其实例在配置更改中保留. fragment
在其布局文件中包含一个RecyclerView
,该文件使用自定义adapter
A single activity
which hosts a fragment
, the instance of which is retained across config changes. The fragment
contains a single RecyclerView
in its layout file that is populated using a custom adapter
向下滚动
每当为这两个视图中的任何一个设置Adapter
时,它们都会向适配器注册以监视数据的更改并在UI上进行更新. ListView
在配置更改时注销自己,
Whenever an Adapter
is set for any of those 2 views, they register themselves with the adapter to monitor changes to the data and update on the UI. ListView
unregisters itself on config changes by
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
...
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
mDataSetObserver = null;
}
...
}
不幸的是,RecyclerView
没有做到这一点
Unfortunately, RecyclerView
doesn't do that
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
}
mFirstLayoutComplete = false;
stopScroll();
mIsAttached = false;
if (mLayout != null) {
mLayout.onDetachedFromWindow(this, mRecycler);
}
removeCallbacks(mItemAnimatorRunner);
}
证明
我多次改变了方向,然后进行了堆转储,并使用Eclipse的MAT读取了它.我确实看到我的活动有很多实例,因为RecyclerView
实例没有unregister
,并且它们对我的活动有很强的引用!
I changed the orientation a good number of times and then took a heap dump, and read it using Eclipse's MAT. I did see that there were a good number of instances of my activity because the RecyclerView
instances didn't unregister
and they have strong references to my activity!!
我错过了什么吗?你们如何确保RecyclerView
不会泄漏您的活动?
Am I missing something? How do you guys make sure that the RecyclerView
doesn't leak your activity?
片段
public class ExampleFragment extends Fragment {
private ExampleAdapter mAdapter = null;
public static ExampleFragment newInstance() {
return new ExampleFragment();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
setupAdapterIfRequired();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_example, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupRecyclerView(getView());
}
private void setupAdapterIfRequired() {
if (mAdapter == null) {
mAdapter = new ExampleAdapter();
}
}
private void setupRecyclerView(View rootView) {
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.list);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(mAdapter);
}
}
推荐答案
将其添加到Fragment
对我来说阻止了泄漏:
Adding this to Fragment
stopped leaks for me:
@Override
public void onDestroyView() {
super.onDestroyView();
recyclerView.setAdapter(null);
}
这篇关于RecyclerView不会在方向更改时从适配器中注销自身的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!