LeakCanary如何解释日志

时间:2016-02-05 19:02:40

标签: android memory-leaks

我的应用程序因内存泄漏问题而被困两天,我在互联网上搜索了解决方案并遇到了一个名为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);

1 个答案:

答案 0 :(得分:0)

创建IndexesAdapter时,不要在构造函数中传递this,而是使用this.getApplicationContext()