Handler简介
【知识点】
- Handler是什么
- 为什么要使用Handler
- Handler / Looper / MessageQueue / Message分别是做什么的
- Handler如何去实现
- 工作原理
- 如何更好的使用
- 扩展及总结
# 1. Handler介绍
在Android开发中,我们常常会使用单独的线程来完成某些操作,比如用一个线程来完成从网络上下载图片,然后显示在一个 ImageView上,在多线程操作时,Android中必须保证以下两点:
- 不要阻塞UI线程
- 不要在UI线程之外更新UI
类比生活中的案例,工作线程(子线程)和 主线程(UI线程)是两个不同的角色,更新UI操作由主线程来负责;工作线程只能是建议主线程发生更改,主线程收到建议后做更新修改,但是它没有权利越俎代庖自己去修改更新主线程内容。
有了以上两点限制,我们在线程之间的消息如何进行传递呢?
Handler登场,Handler作为消息的处理者,主要负责:
- 定时任务:消息调度和在将来某一时间带你执行一个Runnable
- 线程之间消息的处理:多个任务加入到一个队列中执行
# 2. Handler API
Handler是Message的处理器,负责消息的发送和移除
即时消息和延迟消息都会立即被发送出去,只是延迟消息是延迟一定时间做处理(并不是延迟发送,是延迟处理)
- 发送即时消息:
sendMessage(Message msg)
- 发送延迟消息:
sendMessgaeDelayed(Message msg, long time)
- 处理消息:
handleMessage(Message msg)
回调方法 - 移除还未处理的消息:
removeMessage(int what)
thread(start = true) {
Log.d(TAG,"running from sub-thread(): ${Thread.currentThread()}")
// 子线程中发送消息,通知UI更新
handler.sendEmptyMessage(1001) // 发送空消息
val msg = handler.obtainMessage() // 获取消息对象
msg.what = 2000
msg.obj = "要存储的消息" // 任意类型
handler.sendMessage(msg) // 发送消息
handler.sendEmptyMessageAtTime(3000, System.currentTimeMillis() + 3000) // 在指定时间后延迟处理
handler.sendEmptyMessageDelayed(4000,2000) // 延迟多少时间后处理
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3. 更新UI
不能在主线程中直接更新UI
【报错信息】:只有创建视图层次结构的原始线程才能触及它的视图
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
1
修改
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
var rootView: View = binding.root
setContentView(rootView)
// 创建Handler
val handler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Log.d(TAG,"running from UI thread(): ${Thread.currentThread()}")
Log.d(TAG, "handleMessage: ${msg.what}")
// 主线程接到子线程的消息,处理消息,更新UI
if(msg.what == 1001) {
binding.mTextView.text = "📺 iqqcode..."
}
}
}
binding.mButton.setOnClickListener {
thread(start = true) {
Log.d(TAG,"running from sub-thread(): ${Thread.currentThread()}")
// 子线程中发送消息,通知UI更新
handler.sendEmptyMessage(1001)
// TODO 处理耗时操作
}
}
}
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
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
不同的线程在操作
# 4. 实例Demo
# 4.1 请求网路数据
在点击Button时,延迟请求网络数据,此时显示ProgressBar,加载完成后将数据显示到EditText中。
View布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".HandlerTestActivity">
<ProgressBar
android:id="@+id/mProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:max="100"
android:visibility="invisible" />
<Button
android:id="@+id/mButton"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:text="GET Submit" />
<EditText
android:id="@+id/mEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:hint="显示结果" />
</LinearLayout>
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
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
HandlerTestActivity:使用Handler实现异步任务
- 创建Handler成员变量对象, 并重写其handleMessage()
- 在分/主线程创建Message对象
- 使用handler对象发送Message
- 在handleMessage()中处理消息
class HandlerTestActivity : AppCompatActivity() {
private lateinit var binding: ActivityHandlerTestBinding
private val urlString = "http://japi.juhe.cn/qqevaluate/qq?qq=2726109782&key=e6ce0de3a1db3739d4343b9d19a9d61f" // 聚合数据API
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHandlerTestBinding.inflate(layoutInflater)
val rootView: View = binding.root
setContentView(rootView)
binding.mButton.setOnClickListener {
asyncRequestByGet(urlString)
}
}
// 1. 创建Handler成员变量对象, 并重写其handleMessage()
private val handler = object : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what === 2000) {
// 4. 在handleMessage()中处理消息
val result = msg.obj as String
binding.mEditText.setText(result)
binding.mProgressBar.visibility = View.INVISIBLE
}
}
}
/**
* 请求服务器端,得到返回的结果字符串
* @return
* @throws Exception
*/
@Throws(java.lang.Exception::class)
fun asyncRequestByGet(path: String?) {
// 主线程, 显示提示视图(ProgressDialog/ProgressBar)
binding.mProgressBar.visibility = View.VISIBLE;
// OKHttp
val client: OkHttpClient = OkHttpClient.Builder()
.connectTimeout(8000, TimeUnit.MILLISECONDS)
.build()
val request: Request = Request.Builder()
.url(path.toString())
.get()
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.i("TAG", e.message!!)
}
override fun onResponse(call: Call, response: Response) {
val resultData = response.body!!.string()
// 分线程, 联网请求, 并得到响应数据
thread(start = true) {
Thread.sleep(3000)
try {
Log.i("TAG", "asyncRequestByGet: ==> $resultData")
// 2. 在分/主线程创建Message对象
val message = Message.obtain()
message.what = 2000 //标识
message.obj = resultData
// 3. 使用handler对象发送Message
handler.sendMessage(message)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
})
}
}
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
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
# 4.2 数字加减变化Demo
- 初始时:显示10,可以通过点击按钮改变其值
- 点击“自动增加”,每隔1S上面的文本数值增加1,但最大显示20并作出提示
- 点击“自动减少”,每隔1S上面的文本数值减少1,但最小显示1并作出提示
- 点击“暂停”,上面的数值文本不再变化
View布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".HandlerDemoActivity">
<TextView
android:id="@+id/mNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="70dp"
android:gravity="center"
android:text="10"
android:textSize="200sp"
android:textStyle="bold" />
<Button
android:id="@+id/mIncrease"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="70dp"
android:text="自动增加" />
<Button
android:id="@+id/mDecrease"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:text="自动减少" />
<Button
android:id="@+id/mPause"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:enabled="false"
android:text="暂停" />
</LinearLayout>
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
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
HandlerDemoActivity
class HandlerDemoActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var binding: ActivityHandlerDemoBinding
private val WHAT_INCREASE = 100
private val WHAT_DECREASE = 200
private val RAND_COLOR = 300
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHandlerDemoBinding.inflate(layoutInflater)
val rootView: View = binding.root
setContentView(rootView)
// 使用定时器
val timer = Timer();
timer.schedule(object: TimerTask() {
override fun run() {
handler.sendEmptyMessage(RAND_COLOR)
}
}, 1000,1000)
binding.mDecrease.setOnClickListener(this)
binding.mIncrease.setOnClickListener(this)
binding.mPause.setOnClickListener(this)
}
private val handler = object : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
// 得到当前现实的数值
var number = Integer.parseInt(binding.mNumber.text.toString())
when (msg.what) {
// 限制number <= 20
WHAT_INCREASE -> {
if (number == 20) {
// 设置暂停不能操作
binding.mPause.isEnabled = false;
Toast.makeText(this@HandlerDemoActivity, "已经达到最大值", Toast.LENGTH_SHORT).show();
return
}
number++
binding.mNumber.text = number.toString()
// 发送增加的延迟消息
sendEmptyMessageDelayed(WHAT_INCREASE, 1000) // 延迟多少时间后处理
}
WHAT_DECREASE -> {
// 限制number >= 1
if (number == 1) {
//设置暂停不能操作
binding.mPause.isEnabled = false;
Toast.makeText(this@HandlerDemoActivity, "已经达到最小值", Toast.LENGTH_SHORT)
.show();
return
}
number--;
binding.mNumber.text = number.toString();
// 发送减少的延迟消息
sendEmptyMessageDelayed(WHAT_DECREASE, 1000);
}
RAND_COLOR -> {
// 使用rgb混合生成一种新的颜色,Color.rgb生成的是一个int数
binding.mNumber.setTextColor(randomTextColor())
}
}
}
}
/**
* 获取随机rgb颜色值
* @return Int
*/
private fun randomTextColor(): Int {
val random = Random()
// 0-190 ,如果颜色值过大,就越接近白色,就看不清了,所以需要限定范围
val red = random.nextInt(150)
val green = random.nextInt(150)
val blue = random.nextInt(150)
// 使用rgb混合生成一种新的颜色,Color.rgb生成的是一个int数
return Color.rgb(red, green, blue)
}
override fun onClick(v: View?) {
when(v?.id) {
R.id.mIncrease -> {
// 限制Button可操作性
binding.mIncrease.isEnabled = false
binding.mDecrease.isEnabled = true
binding.mPause.isEnabled = true
// 停止减少(移除未处理的减少的消息)
handler.removeMessages(WHAT_DECREASE);
// 发消息(增加)
handler.sendEmptyMessage(WHAT_INCREASE);
}
R.id.mDecrease -> {
// 限制Button可操作性
binding.mIncrease.isEnabled = false
binding.mDecrease.isEnabled = true
binding.mPause.isEnabled = true
// 停止增加(移除未处理的增加的消息)
handler.removeMessages(WHAT_INCREASE);
// 发消息(减少)
handler.sendEmptyMessage(WHAT_DECREASE);
}
R.id.mPause -> {
// 限制Button可操作性
binding.mIncrease.isEnabled = false
binding.mDecrease.isEnabled = true
binding.mPause.isEnabled = true
// 停止增加/减少(移除未处理的减少/增加的消息)
handler.removeMessages(WHAT_INCREASE);
handler.removeMessages(WHAT_DECREASE);
}
}
}
}
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
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
编辑 (opens new window)
上次更新: 2021/06/17, 17:05:09