跟踪 LeakCanary 在 Android 上报告的内存泄漏
Track memory leak reported by LeakCanary on Android
我在 Android 上遇到了 LeakCanary 报告的内存泄漏,但我找不到如何跟踪它。
我有一个名为 Splash 的 activity,它调用一个服务来获取配置数据,然后通过处理程序 ping 回 activity。
//Started like this in the Splash activity
ConfigDumpService.start(this, this, BaseService.DATA_CALLBACK_ACTION_SIMPLE);
其中启动方法是:
public static void start(final Context context, final Handler.Callback handlerCallback, final int callbackAction) {
final Messenger messenger = new Messenger(new Handler(handlerCallback));
final Intent intent = new Intent(context, ConfigDumpService.class);
intent.putExtra(BaseService.PARAM_MESSENGER, messenger);
intent.putExtra(BaseService.PARAM_CALLBACK_ACTION, callbackAction);
context.startService(intent);
}
Splash activity 实现 Handler.Callback
@Override
public boolean handleMessage(final Message msg) {
L.p("In Splash handleMessage(), thread: " + Thread.currentThread().getName());
if (BaseService.DATA_RETRIEVE_SUCCESS == msg.arg1) {
L.p("Message from ConfigService service is SUCCESS!");
startApp();
} else {
L.p("Message from ConfigService service is FAIL!");
showCannotContinueDialog();
}
return true;
}
ConfigDumpService
// Previously fetched some data...
final Message message = Message.obtain();
message.setData(bundle);
if (successful) {
message.arg1 = BaseService.DATA_RETRIEVE_SUCCESS;
} else {
message.arg1 = BaseService.DATA_RETRIEVE_FAIL;
}
try {
final Messenger messenger = startIntent.getParcelableExtra(BaseService.PARAM_MESSENGER);
messenger.send(message);
} catch (RemoteException e) {
L.p("In onHandleIntent RemoteException");
e.printStackTrace();
}
stopSelf();
在 Splash 中创建处理程序的另一个地方 activity 是在短暂延迟后启动主程序 activity:
final Handler handler = new Handler();
final Runnable mRunnable = new Runnable() {
public void run() {
DialogManager.removeAllDialogs();
// Let the base activity know we're just starting the app
BaseActivity.startWithHome(Splash.this, homeId, false, true);
Splash.this.finish();
}
};
handler.postDelayed(mRunnable, splashImageLoadWasSuccessful ? mSplashScreenWaitMilliseconds : 0);
调用堆栈不是很有帮助。如果有任何提示,我将不胜感激。
谢谢
我认为这与实例化 Handler
的方式有关。由于您在 SplashActivity
中实现了 Handler.Callback
,因此您在消息队列中保留了硬引用。相反,您应该实现自己的 Handler
class,如果它是内部 class,则应该是 static
。在这个自定义 Handler
中,你应该有一个 WeakReference
到你传入的 Activity
。 This post 更详细地解释了问题并向你展示了如何解决这个问题。希望这会有所帮助 ;)
我在 Android 上遇到了 LeakCanary 报告的内存泄漏,但我找不到如何跟踪它。
我有一个名为 Splash 的 activity,它调用一个服务来获取配置数据,然后通过处理程序 ping 回 activity。
//Started like this in the Splash activity
ConfigDumpService.start(this, this, BaseService.DATA_CALLBACK_ACTION_SIMPLE);
其中启动方法是:
public static void start(final Context context, final Handler.Callback handlerCallback, final int callbackAction) {
final Messenger messenger = new Messenger(new Handler(handlerCallback));
final Intent intent = new Intent(context, ConfigDumpService.class);
intent.putExtra(BaseService.PARAM_MESSENGER, messenger);
intent.putExtra(BaseService.PARAM_CALLBACK_ACTION, callbackAction);
context.startService(intent);
}
Splash activity 实现 Handler.Callback
@Override
public boolean handleMessage(final Message msg) {
L.p("In Splash handleMessage(), thread: " + Thread.currentThread().getName());
if (BaseService.DATA_RETRIEVE_SUCCESS == msg.arg1) {
L.p("Message from ConfigService service is SUCCESS!");
startApp();
} else {
L.p("Message from ConfigService service is FAIL!");
showCannotContinueDialog();
}
return true;
}
ConfigDumpService
// Previously fetched some data...
final Message message = Message.obtain();
message.setData(bundle);
if (successful) {
message.arg1 = BaseService.DATA_RETRIEVE_SUCCESS;
} else {
message.arg1 = BaseService.DATA_RETRIEVE_FAIL;
}
try {
final Messenger messenger = startIntent.getParcelableExtra(BaseService.PARAM_MESSENGER);
messenger.send(message);
} catch (RemoteException e) {
L.p("In onHandleIntent RemoteException");
e.printStackTrace();
}
stopSelf();
在 Splash 中创建处理程序的另一个地方 activity 是在短暂延迟后启动主程序 activity:
final Handler handler = new Handler();
final Runnable mRunnable = new Runnable() {
public void run() {
DialogManager.removeAllDialogs();
// Let the base activity know we're just starting the app
BaseActivity.startWithHome(Splash.this, homeId, false, true);
Splash.this.finish();
}
};
handler.postDelayed(mRunnable, splashImageLoadWasSuccessful ? mSplashScreenWaitMilliseconds : 0);
调用堆栈不是很有帮助。如果有任何提示,我将不胜感激。
谢谢
我认为这与实例化 Handler
的方式有关。由于您在 SplashActivity
中实现了 Handler.Callback
,因此您在消息队列中保留了硬引用。相反,您应该实现自己的 Handler
class,如果它是内部 class,则应该是 static
。在这个自定义 Handler
中,你应该有一个 WeakReference
到你传入的 Activity
。 This post 更详细地解释了问题并向你展示了如何解决这个问题。希望这会有所帮助 ;)