abler98
@abler98
Software Engineer

Android. Как бороться с подобными утечками памяти?

LeakCanary сообщает об утечках в обработчиках кликов:
@Override
    protected void setupAdapter(CatalogAdapter adapter) {
        adapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener<Item>()
        {
            @Override
            public void onClick(View view, Item item, int position) {
                // Утечка, как я понял, происходит из-за getContext(), даже если никаких нажатий не происходит. Возможно я ошибаюсь и проблема где-то в другом месте.
                Intent intent = new Intent(getContext(), ShowActivity.class);
                intent.putExtra(KEY_ITEM, Parcels.wrap(item));
                startActivity(intent);
            }
        });
    }


Данный метод вызывается в onCreateView:
@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(getLayoutResource(), container, false);
        ...
        setupAdapter(getAdapter());
        ...
        return view;
    }


Адаптер создаётся в onCreate:
@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        ...
        adapter = createAdapter();
        ...
    }


Код BaseAdapter:
public abstract class BaseAdapter<T, VH extends RecyclerView.ViewHolder> extends PaginationAdapter<T, VH>
{
    private List<T> items;
    private Context context;

    private OnItemClickListener<T> onItemClickListener;

    public BaseAdapter(Context ctx) {
        items = new ArrayList<>();
        context = ctx.getApplicationContext();
    }

    @Override
    public int getItemCount() {
        return items.size();
    }
    
    public T getItem(int position) {
        return items.get(position);
    }

    public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    protected void callOnClick(View view, T item, int position) {
        if (onItemClickListener != null) {
            onItemClickListener.onClick(view, item, position);
        }
    }

    protected LayoutInflater getLayoutInflater(View view) {
        return LayoutInflater.from(view.getContext());
    }

    protected Context getContext() {
        return context;
    }

    public interface OnItemClickListener<T>
    {
        void onClick(View view, T item, int position);
    }
}


Вот информация, полученная LeakCanary:
54b165a0fd1c46089c0a4c45118cb2fd.png
  • Вопрос задан
  • 452 просмотра
Решения вопроса 1
@DocentTSR
Android Dev
Сергей,

1. у фрагментов с выставленным setRetainInstance(true) - не должно быть интерфейса/вьюх вообще! Об этом написано в документаци, черным по белому. Это и является вашей утечкой.
дополнительно: И в бэкстек его класть тоже нельзя!

2. любой анонимный/внутренний не статичесикй класс - имеет не явную ссылку на внешний!

3.
- в методе onCreate у фрагмента особо делать ничего не нужно.
- в методе onCreateView нужно создавать тока вьюху, ну или еще такие мелкие операции как setHasOptionsMenu.
- вся основная логика делается в onViewCreated, уже после того как фрагмент приаттачился и создал все вьюхи.

4. на будущее, любой листенер вы можете занулить в методе
onDestroy - Activity
onDestroyView - Fragment

например
adapter.setOnItemClickListener(null)

и важно это делать ДО супер метода!

5. По опыту говорю, все вот эти LeakCanary это для ленивых хипстеров.
Нормальная тулза которая точно вам скажет, что течет, как сильно, и самое главное КТО удерживает эту ссылку покажет - MAT (Memory Analyser Tool) в связке с DDMS, не поленитесь разобраться, на хабре есть кучу статей.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@DJOxid
Можно вызвать view.getContext().
А так походу сохраняется ссылка на внешний объект, у которого вызывается getContext().
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы