网上很多教程,解决Handler造成的内存泄漏问题,基本上是使用弱引用来解决的,但是使用弱引用真的有效么?直接写代码演示,以及分析。
下面分析过程分为4种,第一种是Handler声明成静态的并且弱引用Activity。第二种是handler声明成成员变量的,使用弱引用。第三种是将handler声明成静态的。第四种是声明成普通成员变量,但是在onDestory中移除未执行完的任务。
- 第一种 Handler声明成静态的并且弱引用Activity
下面是代码
` public static class UIHndler extends android.os.Handler{ WeakReference<MainActivity> softReference; public UIHndler(MainActivity mainActivity){ softReference=new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity mainActivity = softReference.get(); if(mainActivity!=null){ // 更新ui mainActivity.handler(); } } }`
- 这种是我们经常写的代码,也是网上很多教程这样写的
- 下面是执行前和执行后的效果图,我们横竖屏切换来完成这个操作。
- 这张图是Activity启动的图
- 可以看到,初始申请内存是3.6m左右。接下来 我们反复的横竖屏切换,拿到下图
- 发现内存没有太多,接下来我们运行下GC,看到下图
- 发下确实没有造成内存泄漏,但是这样能说是弱引用的原因么?因为我们的Handler声明成静态的了
接下来我们演示第二种情况。handler声明成成员变量的,使用弱引用
下面是代码
public class UIHndler extends android.os.Handler{ WeakReference<MainActivity> softReference; public UIHndler(MainActivity mainActivity){ softReference=new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity mainActivity = softReference.get(); if(mainActivity!=null){ // 更新ui mainActivity.handler(); } } }
- 接下来我们还是横竖屏切换,看看内存申请
* 接下来我们Gc
* 发现内存并没有少,这是因为在 hanlder中有延迟任务。那么等延迟任务执行完了之后我们在GC下。下图等延迟任务执行万之后的是GC效果
发现也没有造成内存泄漏,但是得等到handler中的任务都执行完成之后才会清除内存。这样的话性能还是比较低,当然也没有造成内存泄漏。
- 接下来演示第三种情况 将handler声明成静态的
下面是我们的代码
public static android.os.Handler handler=new android.os.Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); tv.setText("dsa"); } };
- 也是反复的横竖屏切换
- 接下来gc
- 发现只要handler声明称static的就不会造成内存泄漏,而且回收很快
那么通过上面的三种情况我们发现。只要是handler声明成static就不会造成内存泄漏,声明成弱引用activity的话,虽然也不会造成内存泄漏,但是需要等到handler中没有执行的任务后才会回收,因此性能不高。
handler之所以造成内存泄漏是因为在activity销毁的时候,handler中有未执行完的任务。那么接下来我们在Activity销毁的时候清空handelr没有执行的任务会是什么效果
接下来我们看第四种情况
handler代码如下
public static android.os.Handler handler=new android.os.Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); tv.setText("dsa"); } };
但是我们在activity的onDestory中添加了如下代码,清空所有handler中没有执行完的任务
protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); }
- 下面是反复横竖屏内存图
- 下面是GC之后的
- 发现也没有内存泄漏
总结
- handler造成内存泄漏是因为在Activity销毁的时候还有未执行完的任务
- 静态static可以解决内存泄漏
- 使用弱引用也可以解决内存泄漏,但是需要等到handler的中任务都执行完,才会释放activity内存,不如直接static释放的快
- handler造成内存泄漏有 两种方案:一种是业务逻辑上,在activity销毁的时候移除所有未执行的任务。一种是从GC上,通过static的Handler或者弱引用解决。但是单独的使用弱引用性能不是太高。
- 欢迎吐槽 QQ2205790462