Ответ 1
Добавление этого параметра в Fragment
прекратило утечки для меня:
@Override
public void onDestroyView() {
super.onDestroyView();
recyclerView.setAdapter(null);
}
Я использовал ListView
в своем приложении для Android и недавно переключился на RecyclerView
и заметил, что он ввел некоторые утечки памяти при изменении ориентации. Дальнейшее исследование стало очевидным.
НАСТРОЙКИ
Единственный activity
, в котором размещается fragment
, экземпляр которого сохраняется во всех конфигурационных изменениях. fragment
содержит один RecyclerView
в своем файле макета, который заполняется с помощью пользовательского adapter
БУРОВАНИЕ ВНИЗ
Всякий раз, когда adapter
устанавливается для любого из этих 2 представлений, они регистрируются с адаптером для мониторинга изменений данных и обновления в пользовательском интерфейсе. 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);
}
Доказательство
Я изменил ориентацию много раз, а затем взял кучу кучи и прочитал его с помощью Eclipse MAT. Я видел, что было много примеров моей активности, потому что экземпляры 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);
}
}
Добавление этого параметра в 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);
}
Надеюсь, что это поможет