我一直被困在我的應用程序的內存泄漏問題兩天,我在互聯網上搜索解決方案,並遇到一個名爲LeakCanary的庫。添加必要的依賴關係後,我再次啓動了應用程序。我正在嘗試通過旋轉手機來檢測泄漏,並在幾次輪換後應用程序顯示日誌。但問題是我不知道如何解釋日誌。LeakCanary如何解釋日誌
這裏是leakCanary顯示日誌:
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: In com.carlos.capstone:1.0:1.
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * com.carlos.capstone.MainActivity has leaked:
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * GC ROOT static android.support.v4.content.LocalBroadcastManager.mInstance
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.support.v4.content.LocalBroadcastManager.mReceivers
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references java.util.HashMap.table
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references array java.util.HashMap$HashMapEntry[].[1]
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references java.util.HashMap$HashMapEntry.key
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.FragmentMain$1.this$0 (anonymous class extends android.content.BroadcastReceiver)
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.FragmentMain.mViewPager
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.support.v4.view.ViewPager.mAdapter
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.FragmentMain$Adapter.mCurrentPrimaryItem
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.FragmentAmerica.mAdapterIndexes
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.adapters.IndexesAdapter.mCursor
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.content.ContentResolver$CursorWrapperInner.mCursor
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.database.sqlite.SQLiteCursor.mDataSetObservable
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.database.DataSetObservable.mObservers
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references java.util.ArrayList.array
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references array java.lang.Object[].[0]
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references android.widget.CursorAdapter$MyDataSetObserver.this$0
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * references com.carlos.capstone.adapters.IndexesAdapter.mContext
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * leaks com.carlos.capstone.MainActivity instance
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Reference Key: 4483f896-bc1c-40a1-9bd6-a96ab0d792a0
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Device: Genymotion generic Google Nexus 5 - 5.1.0 - API 22 - 1080x1920 vbox86p
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Android Version: 5.1 API: 22 LeakCanary: 1.3.1
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Durations: watch=6790ms, gc=116ms, heap dump=1357ms, analysis=4544ms
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Details:
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: * Class android.support.v4.content.LocalBroadcastManager
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: | static $staticOverhead = byte[] [id=0x12d08781;length=40;size=56]
02-05 13:45:14.721 4258-4716/com.carlos.capstone D/LeakCanary: | static
...
與FragmentAmerica片段修訂
package com.carlos.capstone;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.carlos.capstone.adapters.IndexesAdapter;
import com.carlos.capstone.adapters.RssNewsAdapter;
import com.carlos.capstone.customtabs.CustomTabActivityHelper;
import com.carlos.capstone.database.CapstoneContract;
import com.linearlistview.LinearListView;
/**
* Created by Carlos on 19/01/2016.
*/
public class FragmentAmerica extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private LinearListView mVerticalListView;
private LinearListView mIndexesListView;
private ScrollView mScrollView;
private boolean mRotationDone=false;
private static final String KEY_POSX="x_pos";
private static final String KEY_POSY="y_pos";
private static final int NEWS_LOADER=0;
private static final int INDEXES_LOADER=1;
private RssNewsAdapter mAdapter;
private IndexesAdapter mAdapterIndexes;
private static final String selectionNews =CapstoneContract.NewsEntity.REGION + " =?";
private static final String[] selectionArgsNews =new String[]{"AMERICA"};
private static final String selectionIndexes=CapstoneContract.IndexesEntity.REGION + " =?";
private static final String[] selectionArgsIndexes=new String[]{"AMERICA"};
private static final String sortByDateDesc = CapstoneContract.NewsEntity.DATE + " DESC";
private int x;
private int y;
LinearListView.OnItemClickListener mListener = new LinearListView.OnItemClickListener() {
@Override
public void onItemClick(LinearListView parent, View view, int position,long id) {
final TextView tvLink,tvTitle;
tvLink= (TextView) view.findViewById(R.id.txtUrlLink);
tvTitle= (TextView) view.findViewById(R.id.txtTitulo);
Uri uri=null;
uri = Uri.parse(tvLink.getText().toString());
//customization possibilities
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder()
.setToolbarColor(ContextCompat.getColor(getActivity(),R.color.colorPrimary))
.setShowTitle(true)
.build();
CustomTabActivityHelper.openCustomTab(getActivity(), customTabsIntent,uri,
//in case the user doen't have chromium v 45 installed, offer an alternative
//browser experience with WebView
new CustomTabActivityHelper.CustomTabFallback() {
@Override
public void openUri(Activity activity, Uri uri) {
Intent intent=new Intent(getActivity(),DetailsNewsActivity.class);
intent.putExtra("url",tvLink.getText());
intent.putExtra("title",tvTitle.getText());
startActivity(intent);
}
});
}
};
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_america,container,false);
mVerticalListView = (LinearListView) view.findViewById(R.id.verticalList);
mIndexesListView= (LinearListView) view.findViewById(R.id.indexesListAmerica);
mScrollView= (ScrollView) view.findViewById(R.id.scrollViewAm);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
x=mScrollView.getScrollX();
Log.d("VILLANUEVA","x pos:"+mScrollView.getScrollX()+",y pos:"+mScrollView.getScrollY());
y=mScrollView.getScrollY();
}
});
mAdapter =new RssNewsAdapter(getActivity().getApplicationContext(),null,NEWS_LOADER);
mAdapterIndexes=new IndexesAdapter(getActivity().getApplicationContext(),null,INDEXES_LOADER);
//set both adapters
mIndexesListView.setAdapter(mAdapterIndexes);
mVerticalListView.setAdapter(mAdapter);
mVerticalListView.setOnItemClickListener(mListener);
getLoaderManager().initLoader(NEWS_LOADER,null,this);
getLoaderManager().initLoader(INDEXES_LOADER,null,this);
if(savedInstanceState==null) {
} else {
mRotationDone=true;
//scroll to saved position
mScrollView.scrollTo(savedInstanceState.getInt(KEY_POSX),savedInstanceState.getInt(KEY_POSY));
}
Toast.makeText(getActivity(),"onCreateViewAmerica",Toast.LENGTH_SHORT).show();
return view;
}
@Override
public void onResume() {
super.onResume();
Toast.makeText(getActivity(),"onResumeAmerica",Toast.LENGTH_SHORT).show();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_POSX,mScrollView.getScrollX());
outState.putInt(KEY_POSY,mScrollView.getScrollY());
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (id==NEWS_LOADER) {
return new CursorLoader(getActivity().getApplicationContext(),
CapstoneContract.NewsEntity.CONTENT_URI, null, selectionNews, selectionArgsNews, sortByDateDesc);
} else if(id==INDEXES_LOADER) {
return new CursorLoader(getActivity().getApplicationContext(),
CapstoneContract.IndexesEntity.CONTENT_URI,null,selectionIndexes,selectionArgsIndexes,null);
}
return null;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch(loader.getId()) {
case NEWS_LOADER:
mAdapter.swapCursor(data);
break;
case INDEXES_LOADER:
mAdapterIndexes.swapCursor(data);
break;
}
mScrollView.postDelayed(new Runnable() {
@Override
public void run() {
mScrollView.scrollTo(x,y);
}
},200);
Log.d("VILLANUEVA","move to x pos:"+x+",y pos:"+y);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
switch(loader.getId()) {
case NEWS_LOADER:
mAdapter.swapCursor(null);
break;
case INDEXES_LOADER:
mAdapterIndexes.swapCursor(null);
break;
}
}
@Override
public void onDestroy() {
super.onDestroy();
// ExampleApplication application = (ExampleApplication) getActivity().getApplicationContext();
// application.mustDie(this);
}
}
我敢肯定,也是問題與IndexAdapter,如果我註釋掉以下行編碼問題消失;
getLoaderManager().initLoader(INDEXES_LOADER,null,this);
和
return new CursorLoader(getActivity().getApplicationContext(),
CapstoneContract.IndexesEntity.CONTENT_URI,null,selectionIndexes,selectionArgsIndexes,null);
我的內存泄漏消失了。請參閱下面的鏈接解決方案:http://stackoverflow.com/questions/35244301/a-line-of-code-is-causing-memory-leaks-in-my-app/35265828#35265828 –