主要活动在销毁后不会被垃圾收集,因为它是间接由InputMethodManager引用的

hjy*_*hjy 34 android garbage-collection android-activity inputmethodmanager

我从这里开始关注"避免内存泄漏"一文.

然而,所提出的解决方案不能解决泄漏问题.我在Windows XP(SDK 2.3.1)上使用Android模拟器测试了这个.我倾倒堆并检查主要活动仍在堆中(我使用了MAT)

这是我做的:

  1. 使用HelloWorldActivity创建HelloWorld应用程序(它没有子视图)
  2. 运行模拟器并启动HelloWorld应用程序.
  3. 单击后退键关闭它.
  4. 导致DDMS和转储堆中的gc < - 这里我找到了HelloWorldActivity实例.
  5. "GC Roots的路径"显示了以下路径.

HelloWorldActivity < - PhoneWindow $ DecorView < - InputMethodManager

InputMethodManager是一个单例和三个引用DecorView的引用,它引用了HelloWorldActivity.

我无法理解为什么InputMethodManager仍然引用DecorView实例,即使在活动被销毁之后.

是否有任何方法可以确保主要活动在关闭之后被销毁并且GC能够?

Den*_*kiy 18

似乎调用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);
}
Run Code Online (Sandbox Code Playgroud)

Reflector的代码:

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Snicolas取决于它."onStop"只是您的活动不可见的信号."onDestroy"是一个非常活跃的"退出点".调用方法可能会在"onStart"正式未定义之后破坏状态和行为.因此,在将解决方法放在"onStop"中后,应该进行大量测试. (3认同)