在 Chrome 个自定义选项卡中检测到内存泄漏
Memory leak detected in Chrome Custom Tabs
我正在尝试实施 Chrome 自定义选项卡并通过 LeakCanary 检测内存泄漏。
演示应用程序似乎没有泄漏,除非我们添加另一个 Activity 层(即 MainActivity
启动 Activity2
,binds/unbinds 到自定义选项卡服务并启动url——MainActivity
在 demo app 中所做的一切)。
主要Activity 看起来像这样:
public class MainActivity extends Activity implements OnClickListener {
private Button mLaunchButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LeakCanary.install(getApplication());
setContentView(R.layout.main);
mLaunchButton = (Button) findViewById(R.id.launch_button);
mLaunchButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int viewId = v.getId();
if (viewId == R.id.launch_button) {
Intent intent = new Intent(getApplicationContext(), Activity2.class);
startActivity(intent);
}
}
}
从 Activity2
返回到 MainActivity
将导致此泄漏:
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ In org.chromium.customtabsclient.example:1.0:1.
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * org.chromium.customtabsclient.Activity2 has leaked:
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * GC ROOT android.support.customtabs.CustomTabsClient.val$callback (anonymous class extends android.support.customtabs.ICustomTabsCallback$Stub)
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * references org.chromium.customtabsclient.Activity2.this[=12=] (anonymous class extends android.support.customtabs.CustomTabsCallback)
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * leaks org.chromium.customtabsclient.Activity2 instance
https://gist.github.com/abvanpelt/ddbc732f31550b09fc27
我的问题是:这是演示应用程序中的错误吗? (也许 unbindCustomTabsService()
缺少一些需要的拆解?)或者这是 Chrome 自定义选项卡库本身的错误?
谢谢。
示例中的 MainActivity 创建 CustomTabsServiceConnection 和 CustomTabsCallback 的实例作为匿名内部 类。
如果将它们更改为内部静态 类,则删除对 MainActivity 的 this
引用,并将对 MainActivity 的引用设置为WeakReferences,你会看到 LeakCanary 停止报告 MainActivity 泄漏。
现在,如果将 ServiceConnection 设置为监视该对象,您可能仍会看到有关 ServiceConnection 泄漏的泄漏金丝雀报告。原因是它链接到 Chrome 服务,并且在 GC 也运行在服务器端之前无法被 GC 清理。
我创建了一个在循环中绑定和取消绑定服务的测试,并且我已经确认确实在一段时间后收集了 ServiceConnections。
因此,可以改进 Demo,以避免 ServiceConnection 持有对 MainActivity 的引用,避免像 Activity 这样的重对象在服务后长时间处于活动状态已断开连接,这不是自定义选项卡库的问题。
找到这个问题的答案 -
如果您按以下方式启动 customTab
private void launchChromeCustomTab(final Context context, final Uri uri) {
mServiceConnection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
client.warmup(0L);
final CustomTabsIntent intent = new CustomTabsIntent.Builder().build();
intent.launchUrl(context, uri);
mIsCustomTabsLaunched = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
CustomTabsClient.bindCustomTabsService(context, "com.android.chrome", mServiceConnection);
}
那么你需要解绑这个mServiceConnection的onDestroy方法为-
@Override
protected void onDestroy() {
super.onDestroy();
this.unbindService(mServiceConnection);
mServiceConnection = null;
}
那将停止投掷
android.app.ServiceConnectionLeaked: Activity <Your_Activity> has leaked ServiceConnection
我正在尝试实施 Chrome 自定义选项卡并通过 LeakCanary 检测内存泄漏。
演示应用程序似乎没有泄漏,除非我们添加另一个 Activity 层(即 MainActivity
启动 Activity2
,binds/unbinds 到自定义选项卡服务并启动url——MainActivity
在 demo app 中所做的一切)。
主要Activity 看起来像这样:
public class MainActivity extends Activity implements OnClickListener {
private Button mLaunchButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LeakCanary.install(getApplication());
setContentView(R.layout.main);
mLaunchButton = (Button) findViewById(R.id.launch_button);
mLaunchButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int viewId = v.getId();
if (viewId == R.id.launch_button) {
Intent intent = new Intent(getApplicationContext(), Activity2.class);
startActivity(intent);
}
}
}
从 Activity2
返回到 MainActivity
将导致此泄漏:
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ In org.chromium.customtabsclient.example:1.0:1.
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * org.chromium.customtabsclient.Activity2 has leaked:
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * GC ROOT android.support.customtabs.CustomTabsClient.val$callback (anonymous class extends android.support.customtabs.ICustomTabsCallback$Stub)
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * references org.chromium.customtabsclient.Activity2.this[=12=] (anonymous class extends android.support.customtabs.CustomTabsCallback)
09-04 13:49:26.783 10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * leaks org.chromium.customtabsclient.Activity2 instance
https://gist.github.com/abvanpelt/ddbc732f31550b09fc27
我的问题是:这是演示应用程序中的错误吗? (也许 unbindCustomTabsService()
缺少一些需要的拆解?)或者这是 Chrome 自定义选项卡库本身的错误?
谢谢。
示例中的 MainActivity 创建 CustomTabsServiceConnection 和 CustomTabsCallback 的实例作为匿名内部 类。
如果将它们更改为内部静态 类,则删除对 MainActivity 的 this
引用,并将对 MainActivity 的引用设置为WeakReferences,你会看到 LeakCanary 停止报告 MainActivity 泄漏。
现在,如果将 ServiceConnection 设置为监视该对象,您可能仍会看到有关 ServiceConnection 泄漏的泄漏金丝雀报告。原因是它链接到 Chrome 服务,并且在 GC 也运行在服务器端之前无法被 GC 清理。
我创建了一个在循环中绑定和取消绑定服务的测试,并且我已经确认确实在一段时间后收集了 ServiceConnections。
因此,可以改进 Demo,以避免 ServiceConnection 持有对 MainActivity 的引用,避免像 Activity 这样的重对象在服务后长时间处于活动状态已断开连接,这不是自定义选项卡库的问题。
找到这个问题的答案 -
如果您按以下方式启动 customTab
private void launchChromeCustomTab(final Context context, final Uri uri) {
mServiceConnection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
client.warmup(0L);
final CustomTabsIntent intent = new CustomTabsIntent.Builder().build();
intent.launchUrl(context, uri);
mIsCustomTabsLaunched = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
CustomTabsClient.bindCustomTabsService(context, "com.android.chrome", mServiceConnection);
}
那么你需要解绑这个mServiceConnection的onDestroy方法为-
@Override
protected void onDestroy() {
super.onDestroy();
this.unbindService(mServiceConnection);
mServiceConnection = null;
}
那将停止投掷
android.app.ServiceConnectionLeaked: Activity <Your_Activity> has leaked ServiceConnection