Fix memory leaks caused by the android framework
This commit is contained in:
parent
b7f3defd19
commit
dffd572afc
@ -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
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user