我是Android的新手(刚刚完成了我的第一堂课),我正在努力解决内存泄漏问题,我不确定是不是真正的问题。我已经拿了示例代码来阅读联系人数据库,可以通过"下载示例" Android开发者网站上的按钮:
https://developer.android.com/training/contacts-provider/retrieve-details.html
该应用程序可以自行运行(由于READ_CONTACTS权限更改,API 22或更低版本)。我想在我自己的应用程序中使用示例中的主要活动作为主要活动的子项来选择联系人并传回其URI以用于存储一些自定义联系信息。我使用与菜单图标相关联的startActivityForResult()将活动作为主要活动的子项启动。除了在单击联系人时执行finish()而不是在示例应用程序中启动详细信息活动时,我在示例代码中的变化非常小:
原件:
@Override
public void onContactSelected(Uri contactUri) {
if (isTwoPaneLayout && mContactDetailFragment != null) {
// If two pane layout then update the detail fragment to show the selected contact
mContactDetailFragment.setContact(contactUri);
} else {
// Otherwise single pane layout, start a new ContactDetailActivity with
// the contact Uri
Intent intent = new Intent(this, ContactDetailActivity.class);
intent.setData(contactUri);
startActivity(intent);
}
}
新:
@Override
public void onContactSelected(Uri contactUri) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setData(contactUri);
Log.d(LOG_TAG, contactUri.toString());
setResult(RESULT_OK, intent);
finish();
}
UI功能正常工作,我在回调中获得了预期的URI。但是,StrictMode已启用,并且每次调用时都会报告子活动的新实例。即使有多个方向更改,这在原始应用中也不会发生。我在新应用程序中尝试了许多方法来消除这个问题但无济于事。这是我到目前为止所尝试的内容:
我尝试设置意图标志FLAG_ACTIVITY_REORDER_TO_FRONT和FLAG_ACTIVITY_CLEAR_TOP。
我尝试在每次调用活动之前强制进行垃圾收集:
if (BuildConfig.DEBUG)
{
System.gc();
}
startActivityForResult(intent, 1);
我从XML布局中删除了片段定义,并通过FragmentManager替换任何现有实例:
if (getSupportFragmentManager().findFragmentByTag(ADDCONTACTSFRAGMENT_TAG) == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.add_contacts_container, new AddContactsFragment(), ADDCONTACTSFRAGMENT_TAG)
.commit();
}
我读到任何未重新初始化为null的侦听器都可能导致泄漏,因此我尝试为所有侦听器创建成员变量,并在子活动片段的onDestroyView和onDestroy方法中重置它们:
@覆盖 public void onDestroy(){ super.onDestroy();
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
mAdapter.swapCursor(null);
mAdapter = null;
mLoader = null;
mContext = null;
Log.d(LOG_TAG, "In onDestroy()");
}
@Override
public void onDestroyView() {
super.onDestroyView();
getListView().setOnItemClickListener(null);
getListView().setOnScrollListener(null);
mSearchView.setOnQueryTextListener(null);
if (Utils.hasICS()) {
// This listener added in ICS
MenuItemCompat.setOnActionExpandListener(mSearchItem, null);
}
mSearchTerm = null;
mSearchItem = null;
mSearchView = null;
//setListAdapter(null);
mView = null;
mOnContactSelectedListener = null;
mDialogClickListener = null;
mImageLoader.setPauseWork(false);
mImageLoader = null;
if (mAdapterView != null) {
mAdapterView.setOnItemClickListener(null);
mClickView.setOnClickListener(null);
mClickView = null;
mAdapterView = null;
}
Log.d(LOG_TAG, "In onDestroyView()");
}
我还发现了一些unbindDrawables()方法的例子,据说这对于删除所有View对象是必要的,但它对于这个片段的AdapterView并不起作用。这可能是问题吗?
我已经使用设备监视器中的“分配跟踪”选项卡和通过独立MAT应用程序进行堆分析来验证内存中实际存在多个子片段实例,但是我是此时不确定这是否真的是泄漏,或者垃圾收集是否已经取消了片段实例,直到内存受到约束。任何建议都将不胜感激。