android application当按home键时内存泄露,android 开发:InputMethodManager内存泄露解决...

/** * 键盘工具 * Created by jing on 2016/8/19. */

public class TKeybord {

/** * 打开键盘 *@param mEditText *@param mContext */

public static void openKeybord(EditText mEditText, Context mContext)

{

Logger.d("openKeybord");

InputMethodManager imm = (InputMethodManager) mContext

.getSystemService(Context.INPUT_METHOD_SERVICE);

imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);

imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,

InputMethodManager.HIDE_IMPLICIT_ONLY);

}

/** * 关闭软键盘 *@param mEditText *@param mContext */

public static void closeKeybord(EditText mEditText, Context mContext)

{

Logger.d("closeKeybord");

InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);

}

/** * 销毁键盘时候调用 *@param destContext */

// public static void fixInputMethodManagerLeak(Context destContext) {

// if (destContext == null) {

// return;

// }

//

// InputMethodManager imm = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE);

// if (imm == null) {

// return;

// }

//

// String [] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};

// Field f = null;

// Object obj_get = null;

// for (int i = 0;i < arr.length;i ++) {

// String param = arr[i];

// try{

// f = imm.getClass().getDeclaredField(param);

// if (f.isAccessible() == false) {

// f.setAccessible(true);

// } // author: sodino mail:sodino@qq.com

// obj_get = f.get(imm);

// if (obj_get != null && obj_get instanceof View) {

// View v_get = (View) obj_get;

// if (v_get.getContext() == destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的

// f.set(imm, null); // 置空,破坏掉path to gc节点

// } else {

// // 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了

// break;

// }

// }

// }catch(Throwable t){

// t.printStackTrace();

// }

// }

// }

/** * Fix for https://code.google.com/p/android/issues/detail?id=171190 . * * When a view that has focus gets detached, we wait for the main thread to be idle and then * check if the InputMethodManager is leaking a view. If yes, we tell it that the decor view got * focus, which is what happens if you press home and come back from recent apps. This replaces * the reference to the detached view with a reference to the decor view. * * Should be called from {@link Activity#onCreate(android.os.Bundle)} )}. */

public static void fixFocusedViewLeak(Application application) {

// Don't know about other versions yet.

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1|| Build.VERSION.SDK_INT > 23) {

return;

}

final InputMethodManager inputMethodManager =

(InputMethodManager) application.getSystemService(Context.INPUT_METHOD_SERVICE);

final Field mServedViewField;

final Field mHField;

final Method finishInputLockedMethod;

final Method focusInMethod;

try {

mServedViewField = InputMethodManager.class.getDeclaredField("mServedView");

mServedViewField.setAccessible(true);

mHField = InputMethodManager.class.getDeclaredField("mServedView");

mHField.setAccessible(true);

finishInputLockedMethod = InputMethodManager.class.getDeclaredMethod("finishInputLocked");

finishInputLockedMethod.setAccessible(true);

focusInMethod = InputMethodManager.class.getDeclaredMethod("focusIn", View.class);

focusInMethod.setAccessible(true);

} catch (NoSuchMethodException | NoSuchFieldException unexpected) {

Log.e("IMMLeaks", "Unexpected reflection exception", unexpected);

return;

}

application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {

@Override

public void onActivityDestroyed(Activity activity){

}

@Override

public void onActivityStarted(Activity activity){

}

@Override

public void onActivityResumed(Activity activity){

}

@Override

public void onActivityPaused(Activity activity){

}

@Override

public void onActivityStopped(Activity activity){

}

@Override

public void onActivitySaveInstanceState(Activity activity, Bundle bundle){

}

@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

ReferenceCleaner cleaner = new ReferenceCleaner(inputMethodManager, mHField, mServedViewField,

finishInputLockedMethod);

View rootView = activity.getWindow().getDecorView().getRootView();

ViewTreeObserver viewTreeObserver = rootView.getViewTreeObserver();

viewTreeObserver.addOnGlobalFocusChangeListener(cleaner);

}

});

}

static class ReferenceCleaner

implements MessageQueue.IdleHandler, View.OnAttachStateChangeListener,

ViewTreeObserver.OnGlobalFocusChangeListener {

private final InputMethodManager inputMethodManager;

private final Field mHField;

private final Field mServedViewField;

private final Method finishInputLockedMethod;

ReferenceCleaner(InputMethodManager inputMethodManager, Field mHField, Field mServedViewField,

Method finishInputLockedMethod) {

this.inputMethodManager = inputMethodManager;

this.mHField = mHField;

this.mServedViewField = mServedViewField;

this.finishInputLockedMethod = finishInputLockedMethod;

}

@Override public void onGlobalFocusChanged(View oldFocus, View newFocus) {

if (newFocus == null) {

return;

}

if (oldFocus != null) {

oldFocus.removeOnAttachStateChangeListener(this);

}

Looper.myQueue().removeIdleHandler(this);

newFocus.addOnAttachStateChangeListener(this);

}

@Override public void onViewAttachedToWindow(View v) {

}

@Override public void onViewDetachedFromWindow(View v) {

v.removeOnAttachStateChangeListener(this);

Looper.myQueue().removeIdleHandler(this);

Looper.myQueue().addIdleHandler(this);

}

@Override public boolean queueIdle() {

clearInputMethodManagerLeak();

return false;

}

private void clearInputMethodManagerLeak() {

try {

Object lock = mHField.get(inputMethodManager);

// This is highly dependent on the InputMethodManager implementation.

synchronized (lock) {

View servedView = (View) mServedViewField.get(inputMethodManager);

if (servedView != null) {

boolean servedViewAttached = servedView.getWindowVisibility() != View.GONE;

if (servedViewAttached) {

// The view held by the IMM was replaced without a global focus change. Let's make

// sure we get notified when that view detaches.

// Avoid double registration.

servedView.removeOnAttachStateChangeListener(this);

servedView.addOnAttachStateChangeListener(this);

} else {

// servedView is not attached. InputMethodManager is being stupid!

Activity activity = extractActivity(servedView.getContext());

if (activity == null || activity.getWindow() == null) {

// Unlikely case. Let's finish the input anyways.

finishInputLockedMethod.invoke(inputMethodManager);

} else {

View decorView = activity.getWindow().peekDecorView();

boolean windowAttached = decorView.getWindowVisibility() != View.GONE;

if (!windowAttached) {

finishInputLockedMethod.invoke(inputMethodManager);

} else {

decorView.requestFocusFromTouch();

}

}

}

}

}

} catch (IllegalAccessException |InvocationTargetException unexpected) {

Log.e("IMMLeaks", "Unexpected reflection exception", unexpected);

}

}

private Activity extractActivity(Context context) {

while (true) {

if (context instanceof Application) {

return null;

} else if (context instanceof Activity) {

return (Activity) context;

} else if (context instanceof ContextWrapper) {

Context baseContext = ((ContextWrapper) context).getBaseContext();

// Prevent Stack Overflow.

if (baseContext == context) {

return null;

}

context = baseContext;

} else {

return null;

}

}

}

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值