How to find memory leaks using LeakCanary in the Android app?

时间:2016-04-04 18:29:58

标签: android memory-leaks fragment out-of-memory leakcanary

Help please find memory leaks in my app.

LeakCanary:

-static android.app.ActivityThread.sCurrentActivityThread

-references android.utill.ArrayMap.mArray

-reference array java.lang.Object[].1

-references android.app.ActivityThread$ActivityClientRecord.activity

-references MainActivity.tf (tf - my fragment)

-leaks TheaterFragment instance

Example code fragment:

public class TheaterFragment extends Fragment {

Typeface face;
private View view;
private RelativeLayout rl;
private LinearLayout linearLayout;
private int wordLheigh, screenWidht, wordLength, margin, btnHeight;
private String word;
private float scale;
private Animation anim;
private int tangelSound, whooshSound;
private SoundPool mSoundPool2;
private int soundMusic;
private boolean startAnim = false;
private LayoutAnimationController controller;

@Override
public void onStart(){
        super.onStart();
    if (!word.equals("suoh") && startAnim) {

        anim = AnimationUtils.loadAnimation(getActivity(), R.anim.theater);
        anim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mSoundPool2.play(whooshSound, soundMusic, soundMusic, 0, 0, 1);
                rl.setClickable(false);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // linearLayout.startLayoutAnimation();
                startAnim = false;

                Animation anim1 = AnimationUtils.loadAnimation(getActivity(), R.anim.blueword);
                anim1.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        mSoundPool2.play(tangelSound, soundMusic, soundMusic, 0, wordLength, 0.5f);

                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        // rl.setClickable(true);
                    }
                });

                controller = new LayoutAnimationController(anim1, 0.5f);
                linearLayout.setLayoutAnimation(controller);
                linearLayout.setLayoutAnimationListener(new Animation.AnimationListener() {
                    public void onAnimationEnd(Animation _animation) {
                        rl.setClickable(true);

                    }

                    public void onAnimationRepeat(Animation _animation) {
                    }

                    public void onAnimationStart(Animation _animation) {

                    }
                });

                linearLayout.setVisibility(View.VISIBLE);
                linearLayout.startLayoutAnimation();
            }
        });

        rl.setVisibility(View.VISIBLE);
        rl.startAnimation(anim);

    }
}

public void falseClickable(){
    rl.setClickable(false);
    rl.setEnabled(false);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    face = Typefaces.get(getContext(), getContext().getText(R.string.font_droidsans).toString());

    if (Build.VERSION.SDK_INT >= 21)
    {
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();
        mSoundPool2 = new SoundPool.Builder()
                .setAudioAttributes(attributes)
                .build();
    } else {
        mSoundPool2 = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
    }

    tangelSound = mSoundPool2.load(getActivity(), R.raw.tangel, 1);
    whooshSound = mSoundPool2.load(getActivity(), R.raw.whoosh3, 1);

    scale = getArguments().getInt("scale");
    wordLheigh   = getArguments().getInt("wordLheigh");
    screenWidht = getArguments().getInt("screenWidht");
    word = getArguments().getString("word");
    wordLength = word.length();
    soundMusic = getArguments().getInt("soundMusic");
    startAnim = getArguments().getBoolean("startAnim");
    //Log.e("TylyTaay", Integer.toString(FINAL));
    margin = (int) (getResources().getDimension(R.dimen.word_btn_margin)+0.5f);
    btnHeight = (int) (screenWidht / 10 - 4 * margin +0.5f);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.fragment_theater, container, false);
    rl = (RelativeLayout) view.findViewById(R.id.theaterLayout);
    TextView tv1 = (TextView) view.findViewById(R.id.textView1);
    TextView tv2 = (TextView) view.findViewById(R.id.textView1);
    tv1.setTypeface(face);
    tv2.setTypeface(face);

    if (!word.equals("suoh")){
        linearLayout = (LinearLayout) view.findViewById(R.id.clonWordLayout);
        RelativeLayout.LayoutParams lparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, wordLheigh);
        lparams.setMargins(0, screenWidht, 0, 0);
        linearLayout.setLayoutParams(lparams);
        setClon();
    } else {
        rl.setVisibility(View.VISIBLE);
    }
    return view;
}


@Override
public void onDestroy() {
    super.onDestroy();
    linearLayout.removeAllViews();
    linearLayout = null;

    RefWatcher refWatcher = MyApp.getRefWatcher(getActivity());
    refWatcher.watch(this);
}

private void setClon()
{
    Button btn;
    for(int i = 0; i < wordLength; i++)
    {
        btn = new Button(getActivity());
            char[] ch = {word.charAt(i)};
            String st = new String(ch);
        btn.setText(st);
        btn.setGravity(Gravity.CENTER);
        btn.setPadding(0, 0, 0, 0);
        btn.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.word_btn_text_size));
        btn.setBackgroundResource(R.drawable.btn_word_win);
        btn.setTextColor(getResources().getColorStateList(R.color.dark_gray));
        btn.setClickable(false);
        btn.setTypeface(face);
        LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(btnHeight, btnHeight);
        lparams.setMargins(margin, 0,margin, 0);
        linearLayout.addView(btn, lparams); //Добавляем в LinearLayout

    }
    btn = null;
}

public void playSound(int nameSound ) {
    if (soundMusic == 1)
        mSoundPool2.play(nameSound,1,1,0,0,1);}

The sample code in MainActivity, which call the fragment:

private void rightAnswer()
{
    if (imgZoom != null) {
        imgZoomBack(wordL);
    }
    wordL.blockWord(false);
    buttonL.blockBtn(false);
    gridView.setOnItemClickListener(null);

    //tf = new TheaterFragment(scale, wordLheigh, screenWidht, word, bar.tvDiamond, bar.tvLevel, bar.imageView, wordId);
    if (tf == null) {
        tf = new TheaterFragment();
    }

    if (args == null) {
        args = new Bundle();
    }
    args.putFloat("scale", scale);
    args.putInt("wordLheigh", wordLheight);
    args.putInt("screenWidht", screenWidht);
    args.putInt("soundMusic", soundOnOff);
    args.putBoolean("startAnim", true);
    args.putString("word", word);

    //Log.e("TylyTaay", Integer.toString(wordId));
    args.putInt("wordId", wordId);

    tf.setArguments(args);
    args = null;

    getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.frameLayout, tf)
            .commit();

    YoYo.with(Techniques.SlideOutDown)
            .playOn(bar.tgDiamond);
    YoYo.with(Techniques.SlideOutDown)
            .playOn(bar.tgVolume);
    YoYo.with(Techniques.SlideOutDown)
            .playOn(bar.tvDiamond);
    YoYo.with(Techniques.SlideOutDown)
            .playOn(bar.tvLevel);
    bar.imageView.setVisibility(View.VISIBLE);
    YoYo.with(Techniques.SlideInDown)
            .playOn(bar.imageView);}

2 个答案:

答案 0 :(得分:1)

我迟到了,这可能对其他人有帮助。 正如@tsiro LeakCanary提到的那样,它有其自身的错误,您可以转到here了解更多详细信息。

对于您的代码,

getSupportFragmentManager()
        .beginTransaction()
        .add(R.id.frameLayout, tf)
        .commit();

这里您要在FragmentManager中添加片段,但是当活动进入后台或更改/重新初始化片段时,并没有将其删除。

如果使用.add(),请尝试从片段管理器中删除片段。 您可以使用.replace()隐式调用.remove().add()

希望对您有帮助。

答案 1 :(得分:0)

我刚刚注意到我在我的应用程序中使用相同的输出。即使我双重检查我的应用程序可能的内存泄漏,并且我解决了我的代码中发生内存泄漏的实际点,我仍然收到此消息。 ..你不必担心它,可能是LeakCanary库创建的一个bug ...就像我一样忽略它..