Может ли создание imageviews с помощью getApplicationContext() привести к утечкам памяти?

#android #memory-leaks #imageview #profiler

#Android #утечки памяти #просмотр изображений #профилировщик

Вопрос:

У меня есть действие, которое, похоже, приводит к утечке памяти, как показано ниже. Однако утечка canary, похоже, не дает никаких утечек или уведомлений. Если я принудительно собираю мусор, это почти ничего не дает.

утечка памяти

В этом упражнении я динамически создаю imageviews и layouts, а затем помещаю их в scrollview. Пример этого приведен ниже:

 dynamicUI = new DynamicUI(getApplicationContext());

TextView textViewTitle = dynamicUI.headerTextView(exercises[i].name);

// Horizontal layout with tools icon and exercise time text
LinearLayout layoutTime = new LinearLayout(new ContextThemeWrapper(this, R.style.exercise_info_layout), null, 0);
layoutTime.addView(dynamicUI.iconImage(R.drawable.tools_icon));
layoutTime.addView(dynamicUI.captionTextView(exercises[i].time));
layoutTime.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
  

DynamicUI — это класс, который я написал для создания представлений одинаковым образом во всем моем приложении. Вот пример метода:

     public ImageView iconImage(int id){
    ImageView imageView = new ImageView(new ContextThemeWrapper(context, R.style.ButtonImageSmall));
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams((int) (50 * scale), (int) (50 * scale));
    lp.setMargins((int) (10*scale), (int) (10*scale), (int) (10*scale), (int) (10*scale));
    imageView.setLayoutParams(lp);
    imageView.setImageDrawable(context.getResources().getDrawable(id));
    return imageView;
    }
  

Есть несколько представлений, которые я добавляю к дочернему элементу scrollview:

 LinearLayout layoutVertical = dynamicUI.exerciseContainer();
layoutVertical.addView(textViewTitle);
layoutVertical.addView(imageViewCover);
layoutVertical.addView(layoutTime);
layoutVertical.addView(layoutDiff);
scrollLayoutChild.addView(layoutVertical);
  

Существует довольно много таких макетов, 1-5 или около того. Они генерируются из базы данных SQLite:

 DatabaseHelper db = new DatabaseHelper(getApplicationContext());
  

Я попытался присвоить значение null как моим объектам db, так и dynamicUI в конце onCreate (), и, похоже, это ничего не дает:

 // stop memory leak?
dynamicUI = null;
db = null;
  

Ответ №1:

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

Комментарии:

1. Итак, если я использую getApplicationContext, означает ли это, что ImageViews существуют для всего приложения и не могут быть собраны в мусор? И если я использую Activity.this вместо этого, они будут удалены по мере выполнения activities?

2. Я не могу с уверенностью сказать, есть ли другая связь, из-за которой они также остаются резидентными, или нет. Лучший способ проверить это — взять дамп кучи и посмотреть на ссылки. Но поскольку представления принадлежат одному действию, они должны использовать контекст действия для их создания, иначе из-за неправильной инициализации могут возникнуть всевозможные ошибки.