android常见的内存泄漏

内存泄漏是app很容易被忽略的一个大问题,也是查找起来很麻烦的一个bug。但是,我们不得不重视它的存在,必须着手解决所有内存泄漏问题。不然,说不定哪一天,你的app就崩溃了,当然在测试时是不一定会出现崩溃的。

下面说说我在开发中经常碰到的内存泄漏问题,该篇需经常更新记录。


1. context泄漏

在使用单例的时候,我们经常会传入一个Context对象给单例(别问我什么是单例!),对于新手,或者稍不注意的话,会写成这样:

MessageEntry msgEntrys = FeedMessageManager.getInstance(this)
        .getMessageByUserId(Constant.myself.userId, DBHelper.SHOP_MESSAGE_TABLE);


public class FeedMessageManager {
    private static volatile FeedMessageManager dao = null;
    private Context mContext;

    private FeedMessageManager(Context context) {
        mContext = context;
    }

    public static FeedMessageManager getInstance(Context context) {
        FeedMessageManager inst = dao;
        if (inst == null) {
            synchronized (FeedMessageManager.class) {
                inst = dao;
                if (inst == null) {
                    inst = new FeedMessageManager(context);
                    dao = inst;
                }
            }
        }
        return inst;
    }

}

这样就导致了context泄漏!(不要问我为什么一定要传入一个Context),context被传入一个单例中,当activity退出的时候,由于单例中一直存在,一直持有context,导致activity一直无法销毁,当多次进入后,就会产生对应个数的activity,这是要疯了的节奏吗!

所以在单例中,如果要传入context时,要这样:

MessageEntry msgEntrys = FeedMessageManager.getInstance(mContext.getApplicationContext())
        .getMessageByUserId(Constant.myself.userId, DBHelper.SHOP_MESSAGE_TABLE);

传入一个application的context就对了,当application退出时,单例也自然就不存在了!


2.视图监听没有在界面销毁时取消注册

使用过EventBus的同学都知道,在activity或者fragment中的onCreate中需要注册一下:

	EventBus.getDefault().register(this);
然后在onDestroy的时候:

EventBus.getDefault().register(this);

但是,有些大意的同学有时候会忘记写反注册了,然后便导致了内存泄漏。


下面再说个对于键盘监听产生的泄漏问题。

我们一般利用这个办法来监听键盘是处于显示状态还是隐藏状态:

final View rootView = mainView.findViewById(R.id.feedback_root);
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        //比较Activity根布局与当前布局的大小
        if (Utils.isSoftKeybordVisible(rootView)) {
            if (tvSend.getVisibility() == View.VISIBLE) {
                tvSend.setVisibility(View.GONE);
            }
            if (tvHistory.getVisibility() == View.VISIBLE) {
                tvHistory.setVisibility(View.GONE);
            }
        } else {
            if (tvSend.getVisibility() == View.GONE) {
                tvSend.setVisibility(View.VISIBLE);
            }
            if (tvHistory.getVisibility() == View.GONE) {
                tvHistory.setVisibility(View.VISIBLE);
            }
        }
    }
});

具体的意思就是当键盘弹出时,隐藏两个控件,键盘隐藏时,显示两个控件,就这么简单。

但是,当我在分析内存泄漏问题时,发现这个地方导致了内存泄漏。原因就是我们注册了这个布局监听,却没有在界面销毁时却没有取消注册,所以解决办法也很简单,在onDestroy的时候,调用取消监听方法即可:

@Override
public void onDestroy() {
    rootView.getViewTreeObserver().removeOnGlobalLayoutListener(globalLayoutListener);
    super.onDestroy();
}

所以,对于使用各种监听方法的时候,需要注意是否需要在界面销毁时反注册一下呢!?


3.待续
















你可能感兴趣的:(安卓开发,android性能优化,android,内存泄漏,context泄漏)