Android 11 (R) 之 Handler 相关变化

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#getMainLooperView#getHandler(), 或者类似方法显式指定Looper。如果为了兼容性需要隐式线程局部行为,使用 new Handler(Looper.myLooper()) 让读者清楚知道。

Handler(Handler.Callback callback)

这个构造函数废弃了, 在Handler构造期间隐式选择Looper会导致操作悄无声息的丢失(如果Handler不再期待新的任务并退出),崩溃(如果Handler有时在没有激活Looper的主线程中被创建) 或者竞争条件下的bug,处理程序与之关联的线程不是作者预期的,而是使用 Executor 或者使用 Looper#getMainLooperView#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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package com.shoewann.androidrtest

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.ref.WeakReference


class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Handler() --> R 上已废弃
handler1 = object : Handler() {

override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Log.d(TAG, "handler1 handleMessage() called with: message = [$msg]")
if (msg.what == 100) {
Log.d(TAG, "handler1 收到消息: ${msg.obj}")
}
}
}

// Handler(Handler.Callback callback) --> R 上已废弃
handler2 = Handler(Handler.Callback {
Log.d(TAG, "handler 2 handleMessage() called with: message = [$it]")
if (it.what == 200) {
Log.d(TAG, "handler 2 收到消息: ${it.obj}")
return@Callback true
}
false
})

// Handler(Looper looper) R 上替代 Handler()
handler3 = object : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Log.d(TAG, "handler3 handleMessage() called with: msg = [$msg]")
if (msg.what == 300) {
Log.d(TAG, "handler3 收到消息: ${msg.obj}")
}
}
}

// Handler(Looper looper,Handler.Callback callback) R 上替代 Handler(Handler.Callback callback)
handler4 = Handler(Looper.myLooper()!!, Handler.Callback {
Log.d(TAG, "handler4 handleMessage() called with: msg = [$it]")
if (it.what == 400) {
Log.d(TAG, "handler4 收到消息: ${it.obj}")
return@Callback true
}
false
})
// 弱引用 + 静态内部类 -- Handler()
handler5 = Handler5(this@MainActivity)
// 弱引用 + 静态内部类 -- Handler(Looper looper)
handler6 = Handler6(this@MainActivity)

handler7 = Handler(Looper.myLooper()!!, WeakReference(Handler.Callback {
if (it.what == 700) {
Log.d(TAG, "handler7 收到消息: ${it.obj}")
return@Callback true
}
false
}).get())


//弱引用 + 静态内部类 ---> Runnable
myRunnable = MyRunnable(this@MainActivity)

//子线程开始运行
//如果这里直接new Runnable的方式会导致内存泄漏 (后面会说到)
Thread(myRunnable).start()
}

companion object {
private const val TAG = "MainActivity"
private var handler1: Handler? = null
private var handler2: Handler? = null
private var handler3: Handler? = null
private var handler4: Handler? = null
private var handler5: Handler? = null
private var handler6: Handler? = null
private var handler7: Handler? = null
private var myRunnable: MyRunnable? = null

// ------------------------ 弱引用 + 静态内部类 (开始)---------------------------------

private class MyRunnable(activity: MainActivity) : Runnable {
private var activity: WeakReference<MainActivity>? = null

init {
this.activity = WeakReference(activity)
}

override fun run() {
if (activity?.get() == null) return
//模拟网络请求数据---> 耗时操作
Thread.sleep(10000)
val data = "This is a json data from web server"
//发送消息
sendMsg(handler1!!, 100, data)
sendMsg(handler2!!, 200, data)
sendMsg(handler3!!, 300, data)
sendMsg(handler4!!, 400, data)
sendMsg(handler5!!, 500, data)
sendMsg(handler6!!, 600, data)
sendMsg(handler7!!, 700, data)
}
}

// Handler() -- R 上已废弃
private class Handler5(activity: MainActivity) : Handler() {
private var activity: WeakReference<MainActivity>? = null

init {
this.activity = WeakReference(activity)
}

override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Log.d(TAG, "handler5 handleMessage() called with: message = [$msg]")
if (activity?.get() == null) return
if (msg.what == 500) {
Log.d(TAG, "handler5 收到消息: ${msg.obj}")
}
}
}

// Handler(Looper looper) -- R 上替代 Handler()
private class Handler6(activity: MainActivity) : Handler(Looper.myLooper()!!) {
private var activity: WeakReference<MainActivity>? = null

init {
this.activity = WeakReference(activity)
}

override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Log.d(TAG, "handler6 handleMessage() called with: message = [$msg]")
if (activity?.get() == null) return
if (msg.what == 600) {
Log.d(TAG, "handler6 收到消息: ${msg.obj}")
}
}
}
// ------------------------ 弱引用 + 静态内部类 (结束)---------------------------------


private fun sendMsg(handler: Handler, what: Int, obj: String) {
Log.d(TAG, "sendMsg() called with: handler = $handler, what = $what")
val message = handler.obtainMessage()
message.what = what
message.obj = obj
handler.sendMessage(message)
}
}

override fun onBackPressed() {
super.onBackPressed()
Log.d(TAG, "onBackPressed() called")
finish()
}

override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy() called")
handler1?.removeCallbacksAndMessages(null)
handler2?.removeCallbacksAndMessages(null)
handler3?.removeCallbacksAndMessages(null)
handler4?.removeCallbacksAndMessages(null)
handler5?.removeCallbacksAndMessages(null)
handler6?.removeCallbacksAndMessages(null)
handler7?.removeCallbacksAndMessages(null)
}

}

内存泄漏

1. Handler

1
2
3
4
5
6
7
8
9
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);

Toast.makeText(......).show();
textview.setText("xxxx")
}
};

Handler允许我们发送延时消息,如果在延时消息未处理完,而此时Handler所在的Activity被关闭,但因为上述Handler用法则可能会导致内存泄漏。那么,在延时消息未处理完时,Handler无法释放外部类MainActivity的对象,从而导致内存泄漏产生。

2. Runnable

1
2
3
4
5
6
private Runnable mRunnable = new Runnable() {
@Override
public void run() {

}
};

该使用方式是创建了一个内部类,内部类隐性持有外部类对象的引用,如果Activity结束,Runnable里面的任务没有处理完,则不会释放Activity的引用,则Activity无法被回收,造成内存泄漏。

Looper

Looper在android的消息机制充当消息循环的角色,它不停的从MessageQueue中拿出消息,并将消息交给Handler处理。

prepareMainLooper()

在Android 11/ R中,Looper.prepareMainLooper() 已废弃

prepareMainLooper_deprecated.png

方法作用 : 将当前线程初始化为循环程序,将其标记为应用程序的主循环程序
废弃原因 : 应用程序的主循环程序是由Android环境创建的,因此您无需在自己应用里调用此函数。

【源码部分】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. See also: {@link #prepare()}
*
* @deprecated The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
*/
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

ActivityThread是android的主线程,android主线程在创建的时候会在main函数中调用Looper.prepareMainLooper()主动创建一个Looper。

从上面的信息我们可以知道,prepareMainLooper函数中有调用了Looper的prepare来创建Looper

在子线程中直接使用Looper.prepare()方法创建,确保在调用这个方法之后调用loop()方法,并使用quit()方法结束

【源码部分】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
//一个线程中只能有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper
sThreadLocal.set(new Looper(quitAllowed));
}

在线程中我们可以调用Looper.prepare,这个函数中 sThreadLocal.set()中创建一个Looper,该方法不仅创建了Looper,其实也创建了MessageQueue,以及将Looper将当前线程和Looper关联起来了。

【源码部分】

1
2
3
4
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

而Looper的Loop()方法,主要是用来从MessageQueue消息队列里面拿出消息。

以上就是本文的全部内容,感谢您的阅读

本文基于Android R DP1 post,如有不足, 欢迎指正

0%