Android- InputMethodManager Leaks Activity

InputMethodManager 内存泄漏问题

-What Happened

After putting in a new round of background images, I've noticed my app consistently crashing with out of memory exceptions if you exit and then restart the app.  I've tracked this down to the fact that these background images are never being garbage collected, because the entire activity is being kept in memory by the InputMethodManager.  

- Steps to reproduce the problem.
Create a new android project using Eclipse.  
Create a launcher activity.
Add a finalizer:
    protected void finalize()
    {
        Log.i("MainActivity", "Finalized!");
    }
Install and launch the activity
Back out of the activity, in ddms, force garbage collection. 
-- The log message will not activate.
Re-enter the activity, force garbage collection.
-- The log message will now print (for the first instance of the activity)

Exit the activity again.  Force garbage collection.  Dump the hprof profile.  Examine it in the Eclipse Memory Analyzer Tool plugin.  

You will see 
InputMethodManager -> PhoneWindows$DecorView -> <YourActivityName>

Related StackOverflow posts I've found:

http://stackoverflow.com/questions/5038158/main-activity-is-not-garbage-collected-after-destruction-because-it-is-reference

http://stackoverflow.com/questions/5769748/inputmethodmanager-holds-reference-to-the-tabhost-memory-leak-oom-error

 

最后解决方案为

在onDestory中插入调用此方法

 private void fixInputMethodManager() {
        try{
            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);

            Reflector.fixInputMethodManagerViewLeak(ChartActivity.this, (InputMethodManager) imm);
        }catch (Exception ignored){

        }

    }

添加一个inputmethod的处理类,通过反射进行

public class Reflector {

    private static final String TAG = "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) {
        }
    }

    public static void fixInputMethodManagerViewLeak(Context destContext, InputMethodManager imm) {
        if (destContext == null) {
            return;
        }
        String[] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
        Field f = null;
        Object obj_get = null;
        for (String param : arr) {
            try {
                f = imm.getClass().getDeclaredField(param);
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                }
                obj_get = f.get(imm);
                if (obj_get != null && obj_get instanceof View) {
                    View v_get = (View) obj_get;
                    if (v_get.getContext() == destContext) {  // referenced context is held InputMethodManager want to destroy targets
                        f.set(imm, null);  // set empty, destroyed node path to gc
                    } else {
                        // Not want to destroy the target, that is, again into another interface, do not deal with, to avoid affecting the original logic, there is nothing further for the cycle
                        Log.e(TAG, "fixInputMethodManagerLeak break, context is not suitable, get_context=" + v_get.getContext() + " dest_context=" + destContext);
                        break;
                    }
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值