RecyclerView не отменяет регистрацию от адаптера при изменении ориентации

Я использовал ListView в своем приложении для Android и недавно переключился на RecyclerView и заметил, что он ввел некоторые утечки памяти при изменении ориентации. По дальнейшему расследованию, причина стала очевидной

НАСТРОИТЬ

Единственное activity котором размещен fragment , экземпляр которого сохраняется во всех конфигурациях. fragment содержит один RecyclerView в своем файле макета, который заполняется с помощью пользовательского adapter

БУРЕНИЕ ВНИЗ

Всякий раз, когда Adapter настроен для любого из этих двух видов, они регистрируются с адаптером для мониторинга изменений данных и обновления в пользовательском интерфейсе. ListView регистрирует себя при изменении конфигурации на

 @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); ... if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); mDataSetObserver = null; } ... } 

К сожалению, RecyclerView не делает этого

 @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); } 

Доказательство

Я изменил ориентацию много раз, а затем взял кучу кучи и прочитал его, используя MAT Eclipse. Я видел, что было много примеров моей деятельности, потому что экземпляры RecyclerView не unregister и у них есть сильные ссылки на мою деятельность!

Я что-то упускаю? Как вы, ребята, убедитесь, что RecyclerView не утечка активности?

ФРАГМЕНТ

 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); } } 

Solutions Collecting From Web of "RecyclerView не отменяет регистрацию от адаптера при изменении ориентации"

Добавление этого в Fragment перестало утечки для меня:

 @Override public void onDestroyView() { super.onDestroyView(); recyclerView.setAdapter(null); } 

Это не проблема с RecyclerView. Это потому, что вы устанавливаете setRetainInstance(true) .

setRetainInstance() следует использовать только с фрагментом без представления, иначе это приведет к утечке памяти.

Когда активность изменения ориентации будет убита, но просмотр в фрагменте по-прежнему использует контекст из этого действия. Вот почему вы видите утечку памяти.

Я столкнулся с тем же вопросом. Я делаю поиск, но ничего не нахожу в этой теме.

Поэтому я спрашиваю себя: зачем мне нужен контекст в RecyclerView.Adapter? (В ArrayAdapter вы используете его для Infalte некоторого макета). Но в этом новом шаблоне вы можете использовать родительский контекст для раздувания макета:

например

 public class RecyclerViewAdapter extends RecyclerView.Adapter<VH> { @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return LayoutInflater.from(parent.getContext()).inflate(R.layout.item_action, parent, false); } } 

То же самое для привязки

 @Override public void onBindViewHolder(BaseViewHolder holder, int position) { String myString = holder.itemView.getContext().getString(R.string.app); ((Button)holder.itemView).setText(myString); } 

Надеюсь, что это поможет