It's an android framework bug. https://code.google.com/p/android/issues/detail?id=34731
It hasn't been fixed yet, even in support library.
Here is the fix:
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()) {
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();
}
}
}
Call it like this:
@Override
protected void onDestroy() {
super.onDestroy();
//if you get memory leak on configuration change too, remove the if clause.
if (isFinishing()) {
fixInputMethodManagerLeak(this);
}
}
Take a look at this question too.