内存泄漏是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(); }
所以,对于使用各种监听方法的时候,需要注意是否需要在界面销毁时反注册一下呢!?