使用奥托内存泄漏Leakcanary报告 [英] Leakcanary report of memory leak using Otto

查看:219
本文介绍了使用奥托内存泄漏Leakcanary报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在<一个跟进href=\"http://stackoverflow.com/questions/32749332/leakcanary-shows-fragment-leak-with-appcompatactivity-and-fragmentstatepageradap\">my最后一个问题,这里是第二个内存泄漏我无法摆脱的..

我读,我需要注册和注销根据活动和片段的生命周期我静奥托车,所以我增加了注册和取消注册到的onStop和在onStart电话......有一个按钮触发,则所接收到事件由Viewpager里面的一些片段给我下面的内存泄漏:

  D / LeakCanary:在com.doesnthaveadomain.leo.calendartracker:1.0:1。
D / LeakCanary:* com.doesnthaveadomain.leo.calendartracker.MyFragment渗漏:
D / LeakCanary:* GC ROOT静态com.doesnthaveadomain.leo.calendartracker.MyBus.BUS
D / LeakCanary:*引用com.squareup.otto.Bus.handlersByType
D / LeakCanary:*引用java.util.concurrent.ConcurrentHashMap.table
D / LeakCanary:*引用数组java.util.concurrent.ConcurrentHashMap中$节点[] [3]
D / LeakCanary:*引用java.util.concurrent.ConcurrentHashMap中的$ Node.val
D / LeakCanary:*引用java.util.concurrent.CopyOnWriteArraySet.al
D / LeakCanary:*引用java.util.concurrent.CopyOnWriteArrayList.elements
D / LeakCanary:*参考阵列的java.lang.Object [] [0]
D / LeakCanary:*引用com.squareup.otto.EventHandler.target
D / LeakCanary:*泄漏com.doesnthaveadomain.leo.calendartracker.MyFragment实例

我的code ..

MainActivity

进口android.os.Bundle;
进口android.support.v4.app.Fragment;
进口android.support.v4.app.FragmentManager;
进口android.support.v4.app.FragmentStatePagerAdapter;
进口android.support.v4.view.ViewPager;
进口android.support.v7.app.AppCompatActivity;
进口android.view.View;
进口android.widget.Button;进口java.lang.ref.WeakReference;公共类MainActivity扩展AppCompatActivity {    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);        ViewPager mViewPager =(ViewPager)findViewById(R.id.viewpager);
        MyAdapter myAdapter =新MyAdapter(getSupportFragmentManager(),这一点);
        mViewPager.setAdapter(myAdapter);
        mViewPager.setCurrentItem(5);        Button按钮=(按钮)findViewById(R.id.do_something);
        button.setOnClickListener(新View.OnClickListener(){
            @覆盖
            公共无效的onClick(视图v){
                MyBus.getInstance()后(新SomeEvent(东西));
            }
        });
    }    静态类SomeEvent {
        串mString;
        SomeEvent(字符串字符串){
            mString =串;
        }
        公共字符串的getString(){
            返回mString;
        }
    }}类MyAdapter扩展FragmentStatePagerAdapter {    私人诠释mNumberOfViews;
    私人最终的WeakReference&LT; AppCompatActivity&GT; mActivityWeakRef;    公共MyAdapter(FragmentManager FM,
                     AppCompatActivity活动){
        超(FM);        mActivityWeakRef =新的WeakReference&LT; AppCompatActivity&GT;(活动);
        mNumberOfViews = 10;
    }    @覆盖
    公共片段的getItem(INT位置){
        MyFragment myFragment =新MyFragment();
        AppCompatActivity活性= mActivityWeakRef.get();
        如果(活动!= NULL){
            。MyApp.getRefWatcher(mActivityWeakRef.get())腕表(myFragment);
        }
        返回myFragment;
    }    @覆盖
    公众诠释的getCount(){
        返回mNumberOfViews;
    }
}

MyFragment

 进口android.os.Bundle;
进口android.support.v4.app.Fragment;
进口android.view.LayoutInflater;
进口android.view.View;
进口android.view.ViewGroup;进口com.squareup.otto.Subscribe;/ **
 *包含一个简单视图中的占位符片段。
 * /
公共类MyFragment扩展片段{    @覆盖
    公共查看onCreateView(LayoutInflater充气器,容器的ViewGroup,
                             捆绑savedInstanceState){
        返回inflater.inflate(R.layout.fragment_test,集装箱,FALSE);
    }    @覆盖
    公共无效调用onStart(){
        super.onStart();        。MyBus.getInstance()寄存器(本);
    }    @覆盖
    公共无效的onStop(){
        super.onStop();        。MyBus.getInstance()注销(本);
    }    @订阅
    公共无效的onEvent(MainActivity.SomeEvent事件){    }}

布局,以防万一.. MainActivity:

 &LT;的LinearLayout
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent
    机器人:方向=垂直
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android&GT;    &LT; android.support.design.widget.AppBarLayout
        的xmlns:程序=htt​​p://schemas.android.com/apk/res-auto
        的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
        机器人:ID =@ + ID / toolbar_appbar_layout
        机器人:layout_width =match_parent
        机器人:layout_height =WRAP_CONTENT
        机器人:fitsSystemWindows =真正的&GT;        &LT; android.support.v7.widget.Toolbar
            机器人:ID =@ + ID /工具栏
            机器人:layout_width =match_parent
            机器人:layout_height =?ATTR / actionBarSize
            机器人:ATTR / colorPrimary背景=
            应用:layout_scrollFlags =滚动| enterAlways
            应用:主题=@风格/ AppTheme.Toolbar
            应用:popupTheme =@风格/ AppTheme.Toolbar.Popup&GT;        &LT; /android.support.v7.widget.Toolbar>    &LT; /android.support.design.widget.AppBarLayout>    &LT;按钮
        机器人:ID =@ + ID / do_something
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:文字=DO/&GT;    &LT; android.support.v4.view.ViewPager
        机器人:ID =@ + ID / viewpager
        机器人:layout_width =match_parent
        机器人:layout_height =match_parent/&GT;&LT; / LinearLayout中&GT;

片段:

 &LT;的LinearLayout
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent
    机器人:方向=垂直
    机器人:paddingLeft =@扪/ activity_vertical_margin
    机器人:paddingStart =@扪/ activity_vertical_margin
    机器人:paddingRight =@扪/ activity_vertical_margin
    机器人:paddingEnd =@扪/ activity_vertical_margin
    的xmlns:程序=htt​​p://schemas.android.com/apk/res-auto
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android&GT;&LT; / LinearLayout中&GT;


解决方案

您使用的是看在错误的时间参考。你应该只调用手表(事)当你的绝对的肯定,的事情将垃圾收集。为了您的活动和片段,你会想是这样的:

  @覆盖公共无效的onDestroy(){
    super.onDestroy();
    RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
    refWatcher.watch(本);
}

这是从LeakCanary README 如何使用部分

Following up on my last question, here is the second memory leak I can not get rid of..

I read that I need to register and unregister my static Otto bus according to the Activity and Fragment lifecycle, so I added the register and unregister calls to onStop and onStart... Having a button that triggers an event that is then received by some Fragments inside a Viewpager gives me the following memory leak:

D/LeakCanary﹕ In com.doesnthaveadomain.leo.calendartracker:1.0:1.
D/LeakCanary﹕ * com.doesnthaveadomain.leo.calendartracker.MyFragment has leaked:
D/LeakCanary﹕ * GC ROOT static com.doesnthaveadomain.leo.calendartracker.MyBus.BUS
D/LeakCanary﹕ * references com.squareup.otto.Bus.handlersByType
D/LeakCanary﹕ * references java.util.concurrent.ConcurrentHashMap.table
D/LeakCanary﹕ * references array java.util.concurrent.ConcurrentHashMap$Node[].[3]
D/LeakCanary﹕ * references java.util.concurrent.ConcurrentHashMap$Node.val
D/LeakCanary﹕ * references java.util.concurrent.CopyOnWriteArraySet.al
D/LeakCanary﹕ * references java.util.concurrent.CopyOnWriteArrayList.elements
D/LeakCanary﹕ * references array java.lang.Object[].[0]
D/LeakCanary﹕ * references com.squareup.otto.EventHandler.target
D/LeakCanary﹕ * leaks com.doesnthaveadomain.leo.calendartracker.MyFragment instance

My code..

MainActivity

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewPager mViewPager = (ViewPager) findViewById(R.id.viewpager);
        MyAdapter myAdapter = new MyAdapter(getSupportFragmentManager(), this);
        mViewPager.setAdapter(myAdapter);
        mViewPager.setCurrentItem(5);

        Button button = (Button) findViewById(R.id.do_something);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyBus.getInstance().post(new SomeEvent("Something"));
            }
        });
    }

    static class SomeEvent {
        String mString;
        SomeEvent(String string) {
            mString = string;
        }
        public String getString() {
            return mString;
        }
    }

}

class MyAdapter extends FragmentStatePagerAdapter {

    private int mNumberOfViews;
    private final WeakReference<AppCompatActivity> mActivityWeakRef;

    public MyAdapter(FragmentManager fm,
                     AppCompatActivity activity) {
        super(fm);

        mActivityWeakRef = new WeakReference<AppCompatActivity>(activity);
        mNumberOfViews = 10;
    }

    @Override
    public Fragment getItem(int position) {
        MyFragment myFragment = new MyFragment();
        AppCompatActivity activity = mActivityWeakRef.get();
        if (activity != null) {
            MyApp.getRefWatcher(mActivityWeakRef.get()).watch(myFragment);
        }
        return myFragment;
    }

    @Override
    public int getCount() {
        return mNumberOfViews;
    }
}

MyFragment

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.squareup.otto.Subscribe;

/**
 * A placeholder fragment containing a simple view.
 */
public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_test, container, false);
    }

    @Override
    public void onStart() {
        super.onStart();

        MyBus.getInstance().register(this);
    }

    @Override
    public void onStop() {
        super.onStop();

        MyBus.getInstance().unregister(this);
    }

    @Subscribe
    public void onEvent(MainActivity.SomeEvent event) {

    }

}

Layouts, just in case.. MainActivity:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <android.support.design.widget.AppBarLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/toolbar_appbar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true" >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:theme="@style/AppTheme.Toolbar"
            app:popupTheme="@style/AppTheme.Toolbar.Popup">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

    <Button
        android:id="@+id/do_something"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DO"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Fragment:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_vertical_margin"
    android:paddingStart="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_vertical_margin"
    android:paddingEnd="@dimen/activity_vertical_margin"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

</LinearLayout>

解决方案

You are using watching the reference at the wrong time. You should only call watch(thing) when you are absolutely certain that thing will be garbage collected. For your Activities and Fragments, you will want something like this:

@Override public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
    refWatcher.watch(this);
}

That was from the LeakCanary README "How To Use It" section

这篇关于使用奥托内存泄漏Leakcanary报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆