Android学习-Handler内存泄漏
2016/08/20
最近轻微强迫症又犯了,看着编译器上的那些带有黄色感叹号警告就十分难受,于是就下定决心清除我能看到的所有黄色感叹号,一般我不会用像图1中系统提示那些处理方法,
我觉得那是在欺骗自己,可能在处理这些警告上有些费时,但是不管怎样,自己开心就好,.前几天在写一个线程实例的时候
用到了Handler 来传递数据,我之前都是像图2那样写的,图2上已然出现了一个傲娇的黄色感叹号,警告的内容是 This Handler class should be static or leaks might occur (com.example.ndktest.MainActivity.1) 我把我那蹩脚英语能力和有道词典有机统一的结合之后,笼统的明白的这句话的意思是:这个Handler 类应该是静态的,否则可能引起内存泄漏问题,在我颇有成就感的品味被我翻译出来的译文的同时,我又开始蒙圈了,到底是什么原因出现这样奇葩的警告呢,我之前都是这么写的,从来都没有出现过内存泄漏的现象,那这个发生内存泄漏的概率岂不是很低,知其然而不知其所以然,苦恼数微秒之后,我就打开了浏览器,开始刨根问底,许久之后有了些收货.先附上我的测试代码
public class MainActivity extends Activity { public TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { tv.setText("我收到了message"); }; }; }
根据代码可以看出 handler 是一个内部类,内部类分两种,一种是普通内部类,也就是像上面代码里handler这个类那样,另一种是加static关键字的静态内部类,就是那段警告所说的改正后的类的类型.普通内部类隐含保存了外部类的引用,静态内部类就不是这样了,静态内部类只能访问外部类的静态成员.那这跟内存泄漏有什么关系呢,其实思考到这里,答案就已经很明朗了,关键点就在于普通内部类隐含保存了外部类的引用,如果我在上面代码的oncreate函数里添加finish()方法之后,在运行到finish()后,本应该进行对MainActivity 垃圾回收的,但是由于handler内部类有对MainActivity 的引用,所以是MainActivity 对象是不会被回收的,这就造成了内存的泄漏.要解决这样的问题,就要用到弱引用,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,就会回收它的内存,不会考虑内存的充足与否。这样就解决了内存泄漏问题
改后的代码
public class MainActivity extends Activity { public TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } // Handler handler = new Handler() { // // public void handleMessage(android.os.Message msg) { // // tv.setText("我收到了message"); // // }; // }; MyHandler handler = new MyHandler(this); static class MyHandler extends Handler { WeakReference<MainActivity> mActivity; public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); MainActivity a = mActivity.get(); if (a != null) { a.tv.setText("我收到了message"); } } } }