Handler造成Activity泄漏,用弱引用真的有用么?

网上很多教程,解决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或者弱引用解决。但是单独的使用弱引用性能不是太高。

==============================================

在handler中不使用弱引用时,用的是“对象.实例变量”来使用的,那么创建完了没有被GC回收那么造成内存泄漏。而使用了static之后,
静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,

static成员变量:

Java类提供了两种类型的变量:用static关键字修饰的静态变量和不用static关键字修饰的实例变量。静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。对静态变量的引用有两种方式,分别是“类.静态变量"和”对象.静态变量"

实例变量属于对象,只有对象被创建后,实例变量才会被分配内存空间,才能被使用,它在内存中存在多个复制,只有用“对象.实例变量”的方式来引用。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值