Handler的内存泄露几解决办法以及闪屏效果的实现


Handle实现机制涉及的对象:

Message :表示要传递一个消息,(消息对象,内部使用链表数据结构实现一个消息池,用于重复利用, 避免大量创建消息对象,造成对象浪费)

MessageQueue :存放消息对象的消息队列(先进先出)

Looperlooper对象负责管理当前线程的消息队列,用于循环检查消息队列,从消息队列中一个一个的取出消息(Loop 如同一个工人,管MessageQueue 

HandlerHandler对象负责把消息push到消息队列,以及接收Looper从消息队列中读取到的数据

Android启动程序的时候,会在UI线程中创建一个MessageQueue

 


Handler的内存泄露问题:

在使用初次handler的时候,代码会写成如下方式:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    }

  }

 

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

 

    // Post a message and delay its execution for 10 minutes.

    mLeakyHandler.postDelayed(new Runnable() {

      @Override

      public void run() { /* ... */ }

    }, 1000 * 60 * 10);

 

    // Go back to the previous Activity.

    finish();

  }

}

这是会报出警告:警告会出现内存泄露, 

上代码中,当我们执行了Activityfinish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中 又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了 SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露

内存泄露: OS会给所有的进程分配的空间,正在被某一个进程榨干,结果是进程运行的时间越长,占用的存储空间越多,最终占用完全部的存储空间,导致系统崩溃。

出现原因: Handler引用阻止了GCActivity的回收

1java中,非静态(匿名)内部类会默认隐性引用外部类对象,而静态内部类不会引用外部类对象,

2:如果外部类时Activity则会引起Activity内存泄露。

3:当外部类是Activity,在外部类中定义一个Handler 时,Handler对象会持有外部类的引用,在使用时如果要退出Activity时,如果此时Handler还在工作,此时Handler引用持有外部类的引用,此时Activity是无法被回收的,此时就会出现内存泄露。

解决办法:

采用静态内部类与弱引用结合的方式

继承handler的时候,要么放在单独的类文件中,要么放在单独的类文件中,要么就是使用静态内部类,因为静态内部类不会持有外部类的引用,所有不会导致外部类的实例的内存泄露,当在静态静态的内部类中调用外部Activity时,可以使用弱引用来处理,

如下修改后就不会出现内存泄露:

public class HandlerMemoryActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_memory);
        // 使用Handler延时执行一个Runnable10分钟)
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable");
            }
        },1000*60*10);
        finish();// 关闭当前Activity
    }
   private MyHandler handler = new MyHandler(this);
    private static  class  MyHandler extends Handler{
       //创建一个弱引用
        WeakReference<HandlerMemoryActivity> weakReference;

        public  MyHandler (HandlerMemoryActivity activity){
            weakReference = new WeakReference<HandlerMemoryActivity>(activity);
       }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            HandlerMemoryActivity handlerMemoryActivity = weakReference.get();
            if (handlerMemoryActivity!=null){
                // 执行相关的UI操作
            }
        }
    }
}

使用Handler实现闪屏:

当首次注册一个APP时,会有一些提示的信息,提醒用户进行注册或登陆是界面显得很友好。

代码如下:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
              startAnotherActivity();
            }
        },3000);
    }

    private void startAnotherActivity() {
      Intent intent = new Intent(this,Main2Activity.class);
      startActivity(intent);
    }
    private Handler handler = new Handler();
}

在布局文件中使用ImageView

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/e"
    />

将程序运行至模拟器,显示一个图片,经过3秒(主程序设定)后,会返回到下一个业务界面。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值