Browse Source

Fix memory leaks caused by the android framework

master
Anthony Restaino 9 years ago
parent
commit
dffd572afc
  1. 13
      app/src/main/java/acr/browser/lightning/app/BrowserApp.java
  2. 80
      app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java

13
app/src/main/java/acr/browser/lightning/app/BrowserApp.java

@ -1,9 +1,11 @@
package acr.browser.lightning.app; package acr.browser.lightning.app;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import android.webkit.WebView; import android.webkit.WebView;
import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.LeakCanary;
@ -16,9 +18,12 @@ import javax.inject.Inject;
import acr.browser.lightning.BuildConfig; import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.MemoryLeakUtils;
public class BrowserApp extends Application { public class BrowserApp extends Application {
private static final String TAG = BrowserApp.class.getSimpleName();
private static AppComponent mAppComponent; private static AppComponent mAppComponent;
private static final Executor mIOThread = Executors.newSingleThreadExecutor(); private static final Executor mIOThread = Executors.newSingleThreadExecutor();
private static final Executor mTaskThread = Executors.newCachedThreadPool(); private static final Executor mTaskThread = Executors.newCachedThreadPool();
@ -38,6 +43,14 @@ public class BrowserApp extends Application {
if (!isRelease() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (!isRelease() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true); WebView.setWebContentsDebuggingEnabled(true);
} }
registerActivityLifecycleCallbacks(new MemoryLeakUtils.LifecycleAdapter() {
@Override
public void onActivityDestroyed(Activity activity) {
Log.d(TAG, "Cleaning up after the Android framework");
MemoryLeakUtils.clearNextServedView(BrowserApp.this);
}
});
} }
@NonNull @NonNull

80
app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java

@ -0,0 +1,80 @@
package acr.browser.lightning.utils;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Method;
public class MemoryLeakUtils {
private static final String TAG = MemoryLeakUtils.class.getSimpleName();
private static Method sFinishInputLocked = null;
/**
* Clears the mNextServedView and mServedView in
* InputMethodManager and keeps them from leaking.
*
* @param application the application needed to get
* the InputMethodManager that is
* leaking the views.
*/
public static void clearNextServedView(@NonNull Application application) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
// This shouldn't be a problem on N
return;
}
InputMethodManager imm = (InputMethodManager) application.getSystemService(Context.INPUT_METHOD_SERVICE);
if (sFinishInputLocked == null) {
try {
sFinishInputLocked = InputMethodManager.class.getDeclaredMethod("finishInputLocked");
} catch (NoSuchMethodException e) {
Log.d(TAG, "Unable to find method in clearNextServedView", e);
}
}
if (sFinishInputLocked != null) {
sFinishInputLocked.setAccessible(true);
try {
sFinishInputLocked.invoke(imm);
} catch (Exception e) {
Log.d(TAG, "Unable to invoke method in clearNextServedView", e);
}
}
}
public static abstract class LifecycleAdapter 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) {}
}
}
Loading…
Cancel
Save