Подтвердить что ты не робот

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

Я использовал 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);
    }
}
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

Итак, я спрашиваю себя: зачем мне нужен контекст в 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);
}

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