前言
-
多线程的应用在Android开发中是非常常见的,常用方法主要有:
- 继承Thread类
- 实现Runnable接口
- Handler
- AsyncTask
- HandlerThread
-
今天,我将全面解析多线程其中一种常见用法:HandlerThread
由于本文涉及多线程知识和Handler源码解析,所以阅读本文前建议先看:
Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
目录
1. 定义
- Android API提供的一个封装类
- 继承自Thread类
2. 作用
- 通过继承Thread类,实现快速地创建一个带有Looper的新工作线程的功能
- 通过对Handler类使用的封装,实现快速创建Handler并与其他线程进行通信的功能
总结
HandlerThread本质上是通过继承Thread类和封装Handler类的使用,从而使得创建新线程和与其他线程进行通信变得更加方便易用
3. 使用对比
3.1 Thread+Handler用法
因为HandlerThread本质上是继承Thread类和对Handler类使用的封装,所以我们先来看下一般情况下使用Thread+Handler创建线程的用法:
1. 使用Thread类创建一个新的线程
2. 通过创建Handler与其他线程进行通信
如果你还没阅读过Handler的源码,强烈建议先看文章:
Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
Thread+Handler的一般用法
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
在注释里已经非常清晰了,接下来我将继续介绍更加方便易用的HandlerThread
3.2 HandlerThread用法
- HandlerThread的本质:继承Thread类和对Handler类使用的封装。
- 我们先来看HandlerThread的具体使用步骤
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 是不是感觉 HandlerThread更加清晰、简单、易用?!
- 接下来,我们开始对HandlerThread的用法进行源码分析,看一下HandlerThread是如何通过继承Thread类和封装Handler类用法从而使得多线程通信变得如此方便。
4. HandlerThread源码分析
结合HandlerThread上面的用法和本质来看,其实主要是分析:
- 如何创建新线程,即分析
- 1
- 1
- 如何创建Handler并进行通信,即分析
- 1
- 2
- 1
- 2
- 如何结束线程,即分析
- 1
- 1
以下是HandlerThread类的源码(注释标注得非常清晰)
- 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
- 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
注意:
- 在获得mLooper对象的时候存在一个同步的问题:只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,才能将创建的Handler与该Looper绑定
- 解决方案:在run()中成功创建Looper对象后,立即调用notifyAll()通知 getLooper()中的wait()结束等待,并返回run()中成功创建的Looper对象,使得Handler与该Looper对象绑定
5. 实例使用
5.1 实例说明:
- 目的:点击按钮实现延迟操作并更新UI组件
- 使用方法:HandlerThread类
在看下面例子之前我建议你们先去下载Demo,边下边读效果更佳哦!
5.2 具体代码
- 主布局文件
activity_main.xml
- 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
- 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
- MainActivity文件
MainActivity.Java(注释已经标注得非常清楚)
- 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
- 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
5.3 运行结果
5.4 特别注意
从上面的例子中会出现两个细节问题:
5.4.1 细节问题1:内存泄露
在上面的例子中,你会发现出现了严重的警告:
- 1
- 1
即造成了严重的内存泄漏,关于Handler的内存泄露请参考 Android开发:详解Handler的内存泄露
5.4.2 细节问题2:连续发送消息
- 当你连续点击3下时,发现并没有马上按照最新点击的按钮的操作去显示,而是按顺序的一个个显示出来
- 原因:使用HandlerThread时只是开了一个工作线程,当你点击了x下后,只是将x个消息发送到消息队列MessageQueue里排队,等候派发消息给Handler再进行对应的操作
5.5 Demo的源码地址
源码地址放在Github上:Demo for HandlerThread