Android中Handler使用不当导致内存泄露的问题
来源:互联网 发布:淘宝口令怎么用优惠券 编辑:程序博客网 时间:2024/05/05 22:32
参考:
http://www.linuxidc.com/Linux/2013-12/94065.htm
http://www.cnblogs.com/fanglove/archive/2013/03/08/2950102.html
在使用Handler时,通常是new一个内部类(或匿名内部类):
private Handler mHandler=new Handler(){ public void handleMessage(android.os.Message msg) { //Update UI... };};
这时会发现编译器给了个Warning:This Handler class should be static or leaks might occur
这是因为ADT20以后增加了这样一个变化:
New Lint Checks: Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.
翻译过来就是:
Lint会增加一个检查项目即:确保class内部的handler不含有外部类的隐式引用 。
还以上面那段简单的代码为例,当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可能通过Handler来操作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
这么一来,编译器的Warning就好理解了:我们把Handler定义为static,就是为了切断Handler和外部类的联系,这样在外部类对象被GC回收的时候,不会因为Handler无法回收而影响外部类对象的回收。
那么问题又来了,既然现在Handler和外部类没有关系了,怎么去操作外部类中的对象呢?有两种方法:
1.用Handler的post方法把Runnable对象post到主线程,添加到MessageQueue中。
private static Handler handler;public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); handler = new Handler(); //Create a handler to update the UI}void test() { //在新线程中调用该方法 handler.post(new MyRunnable()); //也可以用runOnUiThread(new MyRunnalble());来替换,效果是一样的。}static public class MyRunnable implements Runnable { @Override public void run() { //Update UI... }}
可能有人会说了,这种方法需要把每个消息都封装成对应的Runnable对象post到主线程,没有原来一个Handler处理多个Message的方法来的简单,不过不要紧,我们还有第二种方法。
2.让Handler持有Activity的弱引用。这样以来,在GC回收Activity时,发现Handler持有Activity的弱引用,仍可以将Activity回收掉。
MyHandler mHandler = new MyHandler(this); //传入Activitystatic class MyHandler extends Handler { WeakReference<PopupActivity> mActivity; MyHandler(PopupActivity activity) { //构造方法传入Activity,并生成弱引用 mActivity = new WeakReference<MyActivity>(activity); } @Override public void handleMessage(Message msg) { switch(msg.what){ case 0: //Update UI... break; case 1: //Update UI... break; //... } }}private void test() { //在新线程中调用 mHandler.sendEmptyMessage(0);}
写在最后:一般来说,Handler不定义为static并不会出现太大的问题,postDelayed()方法一般也没什么问题,但在一些特殊的情况下(参考http://www.cnblogs.com/leftwing/archive/2012/02/09/2343420.html),比如postDelayed()嵌套,是肯定会造成内存泄露的。希望以后在写程序时注意这个问题,从小事做起。
- Android中Handler使用不当导致内存泄露的问题
- Android中Handler使用不当引起的内存泄露
- Android中使用中Handler的内存泄露问题
- Android性能优化(三)——Handler使用不当引起的内存泄露
- TransitionDrawable使用不当导致内存泄露
- Handler导致的内存泄露问题
- Handler导致的内存泄露问题
- Android融云使用不当产生的内存泄露和BUG(匿名类回调导致Activity内存泄露)
- 使用Handler可能导致的内存泄露
- 使用Handler导致内存泄露的解决方法
- Android使用Handler造成的内存泄露问题的解决
- android 使用handler内存泄露问题
- Protobuf使用不当导致的程序内存上涨问题
- Android中使用Handler造成内存泄露
- Android中使用Handler造成内存泄露
- android开发中,可能会导致内存泄露的问题
- 【转】android开发中,可能会导致内存泄露的问题
- android开发中,可能会导致内存泄露的问题
- [数据结构复习]广义表
- AssetBundle.Unload(false)的作用
- 宇宙真理系列之人类极限:Stephen Wolfram 还活着的地球人中最聪明的人
- 强制类型转换
- Function 'app_dummy' could not be resolved问题解决
- Android中Handler使用不当导致内存泄露的问题
- static和final的用法
- oracle连接类型
- JAVA利用JDBC对数据库的操作和JDBC编程之事务处理
- UDP-Java-客户机/服务器应用程序
- ironic简介
- 如何给SolidWorks工程图添加条型码?
- c++考悟
- Android学习之Intent机制