Утечка памяти из-за android.widget.BubblePopupHelper

Я использую инструмент MemoryAnalyzer для поиска утечек памяти в приложении Android. Поэтому я запускаю свое приложение, посещаю все действия, а затем отжимаю, пока не дойду до рабочего стола. Затем я использую DDMS для получения дампа памяти (несколько раз нажав Причина GC).

Затем я использую OQL-запрос select * from instanceof android.app.Activity, чтобы найти утечку активности, а затем нажмите Объединить самый короткий путь к GC Roots → исключить все phantom/слабые/мягкие/etc ссылки на утечке объект. И вот у меня есть эта картина:

Итак, кажется, что где-то в системе есть статический объект BubblePopupHelper.sHelper, который сохраняет ссылку на представление EditText из моей активности, в результате чего вся активность протекает! Но что это за BubblePopupHelper? Я не смог найти информацию об этом классе в официальных документах . И как я могу предотвратить сохранение активности в памяти из-за ссылки на этот странный объект?

Я тестировал устройство LG L40, запуская API19

1 ответ

Мои средства обнаружения утечки сообщают о такой же утечке на регулярной основе, только от телефонов LG:

object com.********.SomeActivity
`-mContext of object android.widget.EditText
 `-mView of object android.widget.BubblePopupHelper
 `-sHelper of class android.widget.BubblePopupHelper

Производители хотели бы сменить частные API-интерфейсы Android SDK под капотом. Это утечка памяти, введенная LG.

Из того, что я могу собрать, сфокусированный EditText использует этот BubblePopupHelper, вероятно, чтобы отобразить всплывающее окно copy/paste или текстовый дескриптор. Так как там только один целенаправленный текст редактирования за один раз, они сделали помощника одноэлементным, и он содержит ссылку на последний отредактированный текст редактирования.

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

Как вы можете это исправить? К сожалению, это SDK-код, поэтому, хотя это может быть исправлено в будущих выпусках LG, всегда будут некоторые пользователи с этой ошибкой.

Хотя эта ошибка, разумеется, не ваша ошибка, она по-прежнему является утечкой памяти, которая может протекать в результате превышения ошибок OutOfMemory. Итак, стоит попытаться исправить это,

Есть способ, но это не очень. Когда действие уничтожается, вы можете использовать отражение, чтобы очистить утечку. Например, одним из способов может быть очистка поля sHelper, или другое - очистить поле mView помощника. В любом случае, вы должны попробовать это на устройстве (у меня его нет сейчас) и посмотреть, работает ли он.

private static final Executor backgroundExecutor =
 newCachedThreadPool(backgroundThreadFactory("android-leaks"));
public static void fixLGBubblePopupHelper(final Application application) {
 backgroundExecutor.execute(new Runnable() {
 @Override public void run() {
 final Field sHelperField;
 try {
 Class<!--?--> bubbleClass = Class.forName("android.widget.BubblePopupHelper");
 sHelperField = bubbleClass.getDeclaredField("sHelper");
 sHelperField.setAccessible(true);
 } catch (Exception ignored) {
 // We have no guarantee that this class / field exists.
 return;
 }
 application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksAdapter() {
 @Override public void onActivityDestroyed(Activity activity) {
 try {
 sHelperField.set(null, null);
 } catch (IllegalAccessException ignored) {
 }
 }
 });
 }
 });
}

licensed under cc by-sa 3.0 with attribution.