Instantly share code, notes, and snippets.

Embed
What would you like to do?
"Fix" for InputMethodManager leaking the last focused view: https://code.google.com/p/android/issues/detail?id=171190
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Bundle;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.KITKAT;
public class IMMLeaks {
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;
}
}
}
}
/**
* 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 (SDK_INT < KITKAT || SDK_INT > 22) {
return;
}
final InputMethodManager inputMethodManager =
(InputMethodManager) application.getSystemService(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 LifecycleCallbacksAdapter() {
@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);
}
});
}
}
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
/** Helper to avoid implementing all lifecycle callback methods. */
public class LifecycleCallbacksAdapter implements Application.ActivityLifecycleCallbacks {
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@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 outState) {
}
@Override public void onActivityDestroyed(Activity activity) {
}
}
@ChrisMpitzios

This comment has been minimized.

Show comment
Hide comment
@ChrisMpitzios

ChrisMpitzios May 12, 2015

any ideas for this crash -->Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content

which was caused after calling fixFocusedViewLeak in activity's OnCreate? Tried to add it before and after setcontentview

ChrisMpitzios commented May 12, 2015

any ideas for this crash -->Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content

which was caused after calling fixFocusedViewLeak in activity's OnCreate? Tried to add it before and after setcontentview

@LH23

This comment has been minimized.

Show comment
Hide comment
@LH23

LH23 May 21, 2015

Using this fix and launching a Google Interstitial Ad causes the app to crash, I added a condition to avoid adding the cleaner where activity is instance of com.google.android.gms.ads.AdActivity.

LH23 commented May 21, 2015

Using this fix and launching a Google Interstitial Ad causes the app to crash, I added a condition to avoid adding the cleaner where activity is instance of com.google.android.gms.ads.AdActivity.

@TreyCai

This comment has been minimized.

Show comment
Hide comment
@TreyCai

TreyCai Jun 6, 2015

Here's how I fix:

Use onActivityStarted(Activity) instead of onActivityCreated(Activity, Bundle)


The most common reason why "requestFeature() must be called before adding content" thrown is because we call setContentView(int) before requestWindowFeature(int) . In fact, there're many ways to cause that exception, i.e. getWindow().getDecorView().

In PhoneWindow.getDecorView(), you can see that if mDecor == null, call installDecor().
In installDecor(), if mContentParent is null, then generateLayout(mDecor).
So, if now you call requestWindowFeature(), which means mContentParent is NOT null, then throws AndroidRuntimeException.

The method name in Application.ActivityLifecycleCallbacks is onActivityCreated. How does it know when the activity is being created? There is one line code in Activity.onCreate(Bundle):

getApplication().dispatchActivityCreated(this, savedInstanceState);

Now, everything is clear.

  1. Your target activity calls super.onCreate()
  2. Leads to call ActivityLifecycleCallbacks.onActivityCreated(Activity, Bundle)
  3. Leads to call getDecorView()
  4. Leads to the mContentParent is being generated
  5. Your target activity calls requestWindowFeature(int) (even before setContentView(int))
  6. AndroidRuntimeException thrown

We can call requestWindowFeature() before super.onCreate() to prevent this exception happens, but there're some activities in third-party libraries that we can't control, so I decide to use onActivityStarted instead.

Hope this helpful.

TreyCai commented Jun 6, 2015

Here's how I fix:

Use onActivityStarted(Activity) instead of onActivityCreated(Activity, Bundle)


The most common reason why "requestFeature() must be called before adding content" thrown is because we call setContentView(int) before requestWindowFeature(int) . In fact, there're many ways to cause that exception, i.e. getWindow().getDecorView().

In PhoneWindow.getDecorView(), you can see that if mDecor == null, call installDecor().
In installDecor(), if mContentParent is null, then generateLayout(mDecor).
So, if now you call requestWindowFeature(), which means mContentParent is NOT null, then throws AndroidRuntimeException.

The method name in Application.ActivityLifecycleCallbacks is onActivityCreated. How does it know when the activity is being created? There is one line code in Activity.onCreate(Bundle):

getApplication().dispatchActivityCreated(this, savedInstanceState);

Now, everything is clear.

  1. Your target activity calls super.onCreate()
  2. Leads to call ActivityLifecycleCallbacks.onActivityCreated(Activity, Bundle)
  3. Leads to call getDecorView()
  4. Leads to the mContentParent is being generated
  5. Your target activity calls requestWindowFeature(int) (even before setContentView(int))
  6. AndroidRuntimeException thrown

We can call requestWindowFeature() before super.onCreate() to prevent this exception happens, but there're some activities in third-party libraries that we can't control, so I decide to use onActivityStarted instead.

Hope this helpful.

@Maragues

This comment has been minimized.

Show comment
Hide comment
@Maragues

Maragues Feb 19, 2016

In Genymotion emulator Nexus 4 Android 5.1.0

Object lock = mHField.get(inputMethodManager);

returned null, which caused a NPE when trying to lock on it.

Maragues commented Feb 19, 2016

In Genymotion emulator Nexus 4 Android 5.1.0

Object lock = mHField.get(inputMethodManager);

returned null, which caused a NPE when trying to lock on it.

@vanniktech

This comment has been minimized.

Show comment
Hide comment
@vanniktech

vanniktech Mar 3, 2016

@pyricau should the function fixFocusedViewLeak be called from Application#onCreate or really from every Activity#onCreate(android.os.Bundle)} ?

I'm a bit confused since in the function you register for every activity that was created.

vanniktech commented Mar 3, 2016

@pyricau should the function fixFocusedViewLeak be called from Application#onCreate or really from every Activity#onCreate(android.os.Bundle)} ?

I'm a bit confused since in the function you register for every activity that was created.

@wuairc

This comment has been minimized.

Show comment
Hide comment
@wuairc

wuairc Mar 8, 2016

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

is it a typo, it should be

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

I think.

wuairc commented Mar 8, 2016

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

is it a typo, it should be

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

I think.

@silin

This comment has been minimized.

Show comment
Hide comment
@silin

silin Mar 10, 2016

  1. It seems that you should also unregister the lifecycle callback somewhere;
  2. Current implementation, as I see, should create additional memory leak of LifecycleCallbacksAdapter,
    because you only register new instance in every activity. but never unregister. And it for every creating of activity

silin commented Mar 10, 2016

  1. It seems that you should also unregister the lifecycle callback somewhere;
  2. Current implementation, as I see, should create additional memory leak of LifecycleCallbacksAdapter,
    because you only register new instance in every activity. but never unregister. And it for every creating of activity
@amitshekhariitbhu

This comment has been minimized.

Show comment
Hide comment
@amitshekhariitbhu

amitshekhariitbhu commented May 6, 2016

Simple solution to solve this
InputMethodManagerSolution

@qwertyfinger

This comment has been minimized.

Show comment
Hide comment
@qwertyfinger

qwertyfinger May 17, 2016

Sometimes, when screen is off, I'm getting a couple of such consecutive errors in log, but other than that, app works fine.
Should I pay attention to them then?

IdleHandler threw java.lang.NullPointerException: Null pointer exception during instruction 'monitor-enter v2'
at com.qwertyfinger.lastfmgig_o_meter.util.leak.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:73)
at com.qwertyfinger.lastfmgig_o_meter.util.leak.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
at android.os.MessageQueue.next(MessageQueue.java:216)
at android.os.Looper.loop(Looper.java:151)
at android.app.ActivityThread.main(ActivityThread.java:5637)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)

qwertyfinger commented May 17, 2016

Sometimes, when screen is off, I'm getting a couple of such consecutive errors in log, but other than that, app works fine.
Should I pay attention to them then?

IdleHandler threw java.lang.NullPointerException: Null pointer exception during instruction 'monitor-enter v2'
at com.qwertyfinger.lastfmgig_o_meter.util.leak.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:73)
at com.qwertyfinger.lastfmgig_o_meter.util.leak.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
at android.os.MessageQueue.next(MessageQueue.java:216)
at android.os.Looper.loop(Looper.java:151)
at android.app.ActivityThread.main(ActivityThread.java:5637)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)

@jiantao88

This comment has been minimized.

Show comment
Hide comment
@jiantao88

jiantao88 Sep 26, 2016

Sometimes Sometimes the null pointer will be
E/IMMLeaks( 8218): Unexpected reflection exception
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:72)
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
E/IMMLeaks( 8218): at android.os.MessageQueue.next(MessageQueue.java:211)
E/IMMLeaks( 8218): at android.os.Looper.loop(Looper.java:122)
E/IMMLeaks( 8218): at android.app.ActivityThread.main(ActivityThread.java:5601)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Native Method)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Method.java:372)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
E/IMMLeaks( 8218): Unexpected reflection exception
E/IMMLeaks( 8218): java.lang.NullPointerException: Null pointer exception during instruction 'monitor-enter v2'
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:72)
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
E/IMMLeaks( 8218): at android.os.MessageQueue.next(MessageQueue.java:211)
E/IMMLeaks( 8218): at android.os.Looper.loop(Looper.java:122)
E/IMMLeaks( 8218): at android.app.ActivityThread.main(ActivityThread.java:5601)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Native Method)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Method.java:372)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

jiantao88 commented Sep 26, 2016

Sometimes Sometimes the null pointer will be
E/IMMLeaks( 8218): Unexpected reflection exception
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:72)
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
E/IMMLeaks( 8218): at android.os.MessageQueue.next(MessageQueue.java:211)
E/IMMLeaks( 8218): at android.os.Looper.loop(Looper.java:122)
E/IMMLeaks( 8218): at android.app.ActivityThread.main(ActivityThread.java:5601)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Native Method)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Method.java:372)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
E/IMMLeaks( 8218): Unexpected reflection exception
E/IMMLeaks( 8218): java.lang.NullPointerException: Null pointer exception during instruction 'monitor-enter v2'
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:72)
E/IMMLeaks( 8218): at com.fengjr.mobile.util.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:64)
E/IMMLeaks( 8218): at android.os.MessageQueue.next(MessageQueue.java:211)
E/IMMLeaks( 8218): at android.os.Looper.loop(Looper.java:122)
E/IMMLeaks( 8218): at android.app.ActivityThread.main(ActivityThread.java:5601)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Native Method)
E/IMMLeaks( 8218): at java.lang.reflect.Method.invoke(Method.java:372)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
E/IMMLeaks( 8218): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

@MerlinYu

This comment has been minimized.

Show comment
Hide comment
@MerlinYu

MerlinYu Nov 26, 2016

@trey I found the familiar problem InputMethodManager#mNextServedView leaks.It happened at Android 6.0 MIUI 8.0
mnextserved

MerlinYu commented Nov 26, 2016

@trey I found the familiar problem InputMethodManager#mNextServedView leaks.It happened at Android 6.0 MIUI 8.0
mnextserved

@Fisherman91

This comment has been minimized.

Show comment
Hide comment
@Fisherman91

Fisherman91 Dec 9, 2016

@MerlinYu I also millet 5 frequently found this problem,You solve the above method?

Fisherman91 commented Dec 9, 2016

@MerlinYu I also millet 5 frequently found this problem,You solve the above method?

@swetakadam

This comment has been minimized.

Show comment
Hide comment
@swetakadam

swetakadam Jan 20, 2017

@pyricau it happens on API 23 also

swetakadam commented Jan 20, 2017

@pyricau it happens on API 23 also

@Logan676

This comment has been minimized.

Show comment
Hide comment
@Logan676

Logan676 commented Jan 23, 2017

@MerlinYu same here

@isabsent

This comment has been minimized.

Show comment
Hide comment
@isabsent

isabsent Feb 3, 2017

I have the same screen as MerlinYu on Android emulator API 23.

isabsent commented Feb 3, 2017

I have the same screen as MerlinYu on Android emulator API 23.

@pfugwtg

This comment has been minimized.

Show comment
Hide comment
@pfugwtg

pfugwtg Mar 27, 2017

I have the same problem as HTC M8w on Android 6.0
device-2017-03-27-165625

pfugwtg commented Mar 27, 2017

I have the same problem as HTC M8w on Android 6.0
device-2017-03-27-165625

@mradzinski

This comment has been minimized.

Show comment
Hide comment
@mradzinski

mradzinski Apr 1, 2017

https://gist.github.com/pyricau/4df64341cc978a7de414#file-immleaks-java-L137
@pyricau, this line should be if (SDK_INT < KITKAT || SDK_INT > 23). This leak was finally fixed in Android N 😊

mradzinski commented Apr 1, 2017

https://gist.github.com/pyricau/4df64341cc978a7de414#file-immleaks-java-L137
@pyricau, this line should be if (SDK_INT < KITKAT || SDK_INT > 23). This leak was finally fixed in Android N 😊

@rodgavila

This comment has been minimized.

Show comment
Hide comment
@rodgavila

rodgavila Apr 28, 2017

I'm still seeing this issue on API 25 (7.1.2)

rodgavila commented Apr 28, 2017

I'm still seeing this issue on API 25 (7.1.2)

@mradzinski

This comment has been minimized.

Show comment
Hide comment
@mradzinski

mradzinski May 15, 2017

@rodgavila, that's pretty weird considering I saw the commit that Google used to fix this and which was part of Android N first release. I even tested it on multiple devices and it indeed solved the leak, so you might be having some other leak in reference to other objects.

mradzinski commented May 15, 2017

@rodgavila, that's pretty weird considering I saw the commit that Google used to fix this and which was part of Android N first release. I even tested it on multiple devices and it indeed solved the leak, so you might be having some other leak in reference to other objects.

@treasure-lau

This comment has been minimized.

Show comment
Hide comment
@treasure-lau

treasure-lau Jul 22, 2017

int the custom Application onCreate() method, invoke IMMLeaks.fixFocusedViewLeak(this)

treasure-lau commented Jul 22, 2017

int the custom Application onCreate() method, invoke IMMLeaks.fixFocusedViewLeak(this)

@krmao

This comment has been minimized.

Show comment
Hide comment
@krmao

krmao commented Nov 23, 2017

thank you @TreyCai

@pdalfarr

This comment has been minimized.

Show comment
Hide comment
@pdalfarr

pdalfarr Mar 9, 2018

Thanks a lot for this fix!

Can I kindly ask you to replace

132 * Should be called from {@link Activity#onCreate(android.os.Bundle)} )}.

with

132 * Should be called from {@link Application#onCreate(android.os.Bundle)} )}.

in the source code?

Also, I tried to reproduce on different Android version (using Genymotion emulators):

4.3 (18) : could reproduce. Your code fixed the leak.

4.4.4 (19) : could reproduce. Your code fixed the leak.

5.0 (21) : could reproduce, your code created an exception with a null 'lock' object here:

Object lock = mHField.get(inputMethodManager);
// This is highly dependent on the InputMethodManager implementation.
synchronized (lock) {

Debugger showed that InputMethodManager.isActive() returns false and all fields of InputMethodManager are null, so lock being 'null' seems normal in this case.

03-09 08:08:33.137 9267-9267/com.elementique.calendar A/MessageQueue: IdleHandler threw exception
java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
at <my_app_packagename>.fix.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:77)
at <my_app_packagename>.fix.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:69)
at android.os.MessageQueue.next(MessageQueue.java:211)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

So I added

if(lock != null) {

and no more exception

I am a bit puzzled, as reproducing the leak is not easy (I have to try many time the same 'scenario) and it's even less easy to reproduce the exception about null lock object.

But I think my simple experiments could be of some interest for you, so I am adding the outcome here.

Thanks a lot for this fix anyway :-)

pdalfarr commented Mar 9, 2018

Thanks a lot for this fix!

Can I kindly ask you to replace

132 * Should be called from {@link Activity#onCreate(android.os.Bundle)} )}.

with

132 * Should be called from {@link Application#onCreate(android.os.Bundle)} )}.

in the source code?

Also, I tried to reproduce on different Android version (using Genymotion emulators):

4.3 (18) : could reproduce. Your code fixed the leak.

4.4.4 (19) : could reproduce. Your code fixed the leak.

5.0 (21) : could reproduce, your code created an exception with a null 'lock' object here:

Object lock = mHField.get(inputMethodManager);
// This is highly dependent on the InputMethodManager implementation.
synchronized (lock) {

Debugger showed that InputMethodManager.isActive() returns false and all fields of InputMethodManager are null, so lock being 'null' seems normal in this case.

03-09 08:08:33.137 9267-9267/com.elementique.calendar A/MessageQueue: IdleHandler threw exception
java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
at <my_app_packagename>.fix.IMMLeaks$ReferenceCleaner.clearInputMethodManagerLeak(IMMLeaks.java:77)
at <my_app_packagename>.fix.IMMLeaks$ReferenceCleaner.queueIdle(IMMLeaks.java:69)
at android.os.MessageQueue.next(MessageQueue.java:211)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

So I added

if(lock != null) {

and no more exception

I am a bit puzzled, as reproducing the leak is not easy (I have to try many time the same 'scenario) and it's even less easy to reproduce the exception about null lock object.

But I think my simple experiments could be of some interest for you, so I am adding the outcome here.

Thanks a lot for this fix anyway :-)

@tianfachina

This comment has been minimized.

Show comment
Hide comment
@tianfachina

tianfachina Jul 13, 2018

it don't work,HUAWEI(Honor 6A) on Android 7.0
I use it in Application onCreate() Method
11531502864

tianfachina commented Jul 13, 2018

it don't work,HUAWEI(Honor 6A) on Android 7.0
I use it in Application onCreate() Method
11531502864

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment