Основная активность не является сборкой мусора после уничтожения, поскольку на нее косвенно ссылается InputMethodManager - PullRequest
32 голосов
/ 18 февраля 2011

Я следовал статье «Избегать утечек памяти» из здесь .

Однако предлагаемое решение не решает проблему утечки.Я проверил это с эмулятором Android на Windows XP (SDK 2.3.1).Я сбросил кучу и проверил, что основное действие все еще находится в куче (я использовал MAT)

Вот что я сделал:

  1. создание приложения HelloWorld с HelloWorldActivity (у него нет дочерних представлений))
  2. Запустите эмулятор и запустите приложение HelloWorld.
  3. закройте его, нажав клавишу возврата.
  4. Вызовите gc в DDMS и выгрузите кучу <- Здесь я нашел экземпляр HelloWorldActivity.</li>
  5. «Путь к корням GC» из него показывает следующий путь.

HelloWorldActivity <- PhoneWindow $ DecorView <- InputMethodManager </p>

InputMethodManager является одиночным и содержит три ссылкив DecorView, который ссылается на HelloWorldActivity.

Я не могу понять, почему InputMethodManager все еще ссылается на экземпляр DecorView даже после того, как действие уничтожено.

Есть ли способ убедиться, что основное действие уничтожено и способно GC после его закрытия?

Ответы [ 3 ]

16 голосов
/ 27 мая 2014

Кажется, что вызов метода InputMethodManager 'windowDismissed' и 'startGettingWindowFocus' делает все.

Примерно так:

@Override
protected void onDestroy()
{
    super.onDestroy();
    //fix for memory leak: http://code.google.com/p/android/issues/detail?id=34731
    fixInputMethodManager();
}

private void fixInputMethodManager()
{
    final Object imm = getSystemService(Context.INPUT_METHOD_SERVICE);

    final Reflector.TypedObject windowToken
        = new Reflector.TypedObject(getWindow().getDecorView().getWindowToken(), IBinder.class);

    Reflector.invokeMethodExceptionSafe(imm, "windowDismissed", windowToken);

    final Reflector.TypedObject view
        = new Reflector.TypedObject(null, View.class);

    Reflector.invokeMethodExceptionSafe(imm, "startGettingWindowFocus", view);
}

Код рефлектора:

public static final class TypedObject
{
    private final Object object;
    private final Class type;

    public TypedObject(final Object object, final Class type)
    {
    this.object = object;
    this.type = type;
    }

    Object getObject()
    {
        return object;
    }

    Class getType()
    {
        return type;
    }
}

public static void invokeMethodExceptionSafe(final Object methodOwner, final String method, final TypedObject... arguments)
{
    if (null == methodOwner)
    {
        return;
    }

    try
    {
        final Class<?>[] types = null == arguments ? new Class[0] : new Class[arguments.length];
        final Object[] objects = null == arguments ? new Object[0] : new Object[arguments.length];

        if (null != arguments)
        {
            for (int i = 0, limit = types.length; i < limit; i++)
            {
                types[i] = arguments[i].getType();
                objects[i] = arguments[i].getObject();
            }
        }

        final Method declaredMethod = methodOwner.getClass().getDeclaredMethod(method, types);

        declaredMethod.setAccessible(true);
        declaredMethod.invoke(methodOwner, objects);
    }
    catch (final Throwable ignored)
    {
    }
}
3 голосов
/ 18 февраля 2011

Я заметил, что некоторые слушатели имеют тенденцию сохранять ссылку на действие при некоторых обстоятельствах, даже после того, как действие предположительно было закончено. Поворот от портрета к пейзажу может, например, перезапустить вашу деятельность, и, если вам не повезло, ваша первая активность не правильно сконфигурирована (в моем случае из-за того, что некоторые слушатели все еще ссылаются на нее).

Будучи бывшим программистом на C / C ++, мне имплантировали в позвоночник «отключить» любых слушателей в Activity.onDestroy () (setXyzListener(null)).

EDIT:

Так же, как Тед прокомментировал ниже, нужно действительно «устанавливать» и «отменять» слушателей в Activity.onResume() и Activity.onPause() соответственно.

3 голосов
/ 18 февраля 2011

Если я правильно понимаю ваш вопрос, ответ: нет, вы не можете убедиться, что задание выполнено. Метод onDestroy () вашей активности должен был быть вызван, и действие было остановлено. Это не означает, однако, что процесс завершен или что активность активирована; это управляется системой.

...