-
-
Save jankovd/a210460b814c04d500eb12025902d60d to your computer and use it in GitHub Desktop.
[MIT License] Fixes a leak caused by SemEmergencyManager, see https://github.com/square/leakcanary/issues/762
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class App extends Application { | |
@Override protected void onCreate(Context context) { | |
SemEmergencyManagerLeakingActivity.applyFix(this); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Fixes a leak caused by SemEmergencyManager. Tracked at https://github.com/square/leakcanary/issues/762 */ | |
public final class SemEmergencyManagerLeakingActivity implements Application.ActivityLifecycleCallbacks { | |
private Application application; | |
private SemEmergencyManagerLeakingActivity(Application application) { | |
this.application = application; | |
} | |
public static void applyFix(Application application) { | |
if (MANUFACTURER.equals("samsung") && SDK_INT >= KITKAT && SDK_INT <= N) { | |
application.registerActivityLifecycleCallbacks(new SemEmergencyManagerLeakingActivity(application)); | |
} | |
} | |
@Override public void onActivityDestroyed(Activity activity) { | |
try { | |
swapActivityWithApplicationContext(); | |
} catch (Exception ignored) { | |
// the same result is expected on subsequent tries. | |
} | |
application.unregisterActivityLifecycleCallbacks(this); | |
} | |
private void swapActivityWithApplicationContext() | |
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { | |
Class<?> semEmergencyManagerClass = Class.forName("com.samsung.android.emergencymode.SemEmergencyManager"); | |
Field sInstanceField = semEmergencyManagerClass.getDeclaredField("sInstance"); | |
sInstanceField.setAccessible(true); | |
Object sInstance = sInstanceField.get(null); | |
Field mContextField = semEmergencyManagerClass.getDeclaredField("mContext"); | |
mContextField.setAccessible(true); | |
mContextField.set(sInstance, application); | |
} | |
@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) {} | |
} |
galaxy Note 5 ,The problem still exists
If you unregister after one activity is destroyed, does that mean subsequent activities might leak?
If you unregister after one activity is destroyed, does that mean subsequent activities might leak?
sInstance mContext field is updated with application context. other activities use same instance so does not leak.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Do you intend this to be open source? If so, what license is it available under? My understanding is that by default gists are copyrighted, not open source, and may not be reproduced or distributed without permission.