
Handler 类,相信大家并不陌生,也应当耳熟能详,且铭记于心
几乎项目中使用频率较高,同时也是面试时常挂嘴边的必考知识点
今天我们来谈谈在Android 11/R 上 Handler 相关变化
Handler
Handler 可让您发送和处理 Message 和 Runnable 与线程的 MessageQueue 关联的对象。每个处理程序
实例与单个线程以及该线程的消息相关联排队。创建新的处理程序时,它会绑定到 Looper。它将消息和可运行消息传递到该 Looper 的消息排队并在该 Looper 的线程上执行它们。
Android 11/R DP1 的发布,参考以下的差异报告 官方对 Handler 类的两个构造函数进行了更改,一个是 Handler(),另一个是 Handler(Handler.Callback callback)
结果也就是将这两个方法 —— 废!弃!了!
Changed Constructors | |
---|---|
Handler() | Now deprecated. |
Handler(Callback) | Now deprecated. |
- Handler 差异报告
Handler()
这个构造函数废弃了, 在Handler构造期间隐式选择Looper会导致操作悄无声息的丢失(如果Handler不再期待新的任务并退出),崩溃(如果Handler有时在没有激活Looper的主线程中被创建) 或者竞争条件下的bug,处理程序与之关联的线程不是作者预期的,而是使用 Executor 或者使用 Looper#getMainLooper、View#getHandler(), 或者类似方法显式指定Looper。如果为了兼容性需要隐式线程局部行为,使用 new Handler(Looper.myLooper()) 让读者清楚知道。
Handler(Handler.Callback callback)
这个构造函数废弃了, 在Handler构造期间隐式选择Looper会导致操作悄无声息的丢失(如果Handler不再期待新的任务并退出),崩溃(如果Handler有时在没有激活Looper的主线程中被创建) 或者竞争条件下的bug,处理程序与之关联的线程不是作者预期的,而是使用 Executor 或者使用 Looper#getMainLooper、View#getHandler(), 或者类似方法显式指定Looper。如果为了兼容性需要隐式线程局部行为,使用 new Handler(Looper.myLooper(), callback) 让读者清楚知道。
通过上面的官方文档介绍
那么在Android 11 /R 之后创建Handler构造函数
Handler()变更为 new Handler(Looper.myLooper())Handler(Handler.Callback callback)变更为 new Handler(Looper.myLooper(), callback)
相关示例
1 | package com.shoewann.androidrtest |
内存泄漏
1. Handler
1 | private Handler handler = new Handler() { |
Handler允许我们发送延时消息,如果在延时消息未处理完,而此时Handler所在的Activity被关闭,但因为上述Handler用法则可能会导致内存泄漏。那么,在延时消息未处理完时,Handler无法释放外部类MainActivity的对象,从而导致内存泄漏产生。
2. Runnable
1 | private Runnable mRunnable = new Runnable() { |
该使用方式是创建了一个内部类,内部类隐性持有外部类对象的引用,如果Activity结束,Runnable里面的任务没有处理完,则不会释放Activity的引用,则Activity无法被回收,造成内存泄漏。
Looper
Looper在android的消息机制充当消息循环的角色,它不停的从MessageQueue中拿出消息,并将消息交给Handler处理。
prepareMainLooper()
在Android 11/ R中,Looper.prepareMainLooper()
已废弃
方法作用 : 将当前线程初始化为循环程序,将其标记为应用程序的主循环程序
废弃原因 : 应用程序的主循环程序是由Android环境创建的,因此您无需在自己应用里调用此函数。
【源码部分】
1 | /** |
ActivityThread是android的主线程,android主线程在创建的时候会在main函数中调用Looper.prepareMainLooper()主动创建一个Looper。
从上面的信息我们可以知道,prepareMainLooper函数中有调用了Looper的prepare来创建Looper
在子线程中直接使用Looper.prepare()方法创建,确保在调用这个方法之后调用loop()方法,并使用quit()方法结束
【源码部分】
1 | /** Initialize the current thread as a looper. |
在线程中我们可以调用Looper.prepare,这个函数中 sThreadLocal.set()中创建一个Looper,该方法不仅创建了Looper,其实也创建了MessageQueue,以及将Looper将当前线程和Looper关联起来了。
【源码部分】
1 | private Looper(boolean quitAllowed) { |
而Looper的Loop()方法,主要是用来从MessageQueue消息队列里面拿出消息。
以上就是本文的全部内容,感谢您的阅读
本文基于Android R DP1 post,如有不足, 欢迎指正