1. <br />**附上代码实例**<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/23128312/1637498681155-b6772481-75da-4051-874a-6efa533191b4.png#clientId=uda5874a0-5fa5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=534&id=u5d3f22d7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1068&originWidth=480&originalType=binary&ratio=1&rotation=0&showTitle=false&size=23303&status=done&style=none&taskId=ueebc2e4b-c937-483b-a87a-e0e47cfd7e6&title=&width=240)<br />[https://github.com/ABOXOFJAM/Kotlin-Thread](https://github.com/ABOXOFJAM/Kotlin-Thread)

UI线程和主线程的区别

很多地方可以看到UI线程等于主线程,当是有的时候并不相等
但是区别可以忽略,只要不构建rom或者自定义安卓系统就可以默认他们相等
image.png
[

](https://blog.csdn.net/linjcai/article/details/81245418)

安卓单线程模型

应用启动 -> 创建主线程 -> 主线程向UI组件分发事件(包括绘制事件)
在这个线程里 应用和Android UI toolkit(android.widget和android.view的包)交互

系统不会为每个组件单独创建线程,在同一个进程的UI组件都会在UI线程实例化
系统对每个组件的调用都是从UI线程分发出去的
这样的结果就是,响应系统回调的方法(比如监听用户点击的onKeyDown()和各种生命周期回调),永远在UI线程里运行

只适合功能简单的app的实现,因为如果所有工作都在UI线程做的话,比如比较耗时的网络请求的时候,或者数据库查询,会阻塞UI线程,导致事件停止分发(包括UI的绘制事件),导致用户看到的节目看你就像卡住一样,如果UI线程阻塞的时间太长了(超过大约5秒),用户会看到应用无响应的提示框

Android UI toolkit不是线程安全的,不能从非UI线程来操纵UI组
所以安卓单线程模型有两条原则

  1. 不要阻塞UI线程
  2. 不要在UI线程之外访问Android UI toolkit

使用Worker线程

根据单线程模型的原则,保证应用的响应性,不能阻塞UI线程,所以如果操作不是即时的,就应该把操作放到另外单独的线程中(叫background线程或worker线程)
比如image.png
上面的例子新开了一个线程 虽然确实没对UI线程造成阻塞,但是因为Android UI toolkit不是线程安全的,所以违反了第二个原则,从非UI线程访问UI组件会导致未定义和不能预料的行为
image.png
image.png
还有Handler.post
Handler.postDelayed

使用例比较

Activity.runOnUiThread(Runnable)

View.Post(Runnable)

其实现内部也是用到Handler.Post
具体如图
image.png
可以看到这里,如果attachInfo不等于null就调用他内部的mHandler.post,否则就从getRunQueue中(消息队列?)找Handler来post,保证了在UI线程中执行
看下getRunQueue的源码
image.png
可以看到返回的就是HandlerActionQueue对象实例,也就是说调用的说他的Post的方法,继续跟进HandlerActionQueue
image.png
可以看到它是通过HandlerActionQueue缓存起来,具体执行的时机我们继续跟进
image.png
缓存起来的runnable还是通过handler来执行,执行还是由dispatchAttachedToWindow执行

回到最开始VIew.Post的源码中
mAttachInfo我们不知道是啥,进一步来看它是怎么被赋值的
image.png
这里可以看到他说在dispatchAttachedToWindow中调用的
执行顺序是
View初始化 -> 调用ViewRootImpl的performTraversals ->调用dispatchAttachedToWindow
总而言之就是打开一个activity时如果调用post方法时还没有开始执行dispatchAttachedToWindow就先调用getRunQueue.post(action)缓存起来,当执行到dispatchAttachedToWindow时再执行handler的post,如果到达就直接执行handler.post
image.png
image.png

Handler.Post(Runnable)

https://www.yuque.com/xiangzi-31wyc/kb/fc1r56/edit

如今如安卓的发展
AsyncTask,RxJava,kotlin的Flow等都能更好地解决这些问题

UI线程的通信

只有在UI线程中的对象才能操作UI线程中的对象,为了将非UI线程中的数据传送到UI线程,可以使用一个Handler运行中UI线程中
一个Handler对象负责接收消息然后处理消息
可以为新线程创建一个Handler,也可以创建一个Handler将它和已有的线程连接
如果将一个Handler和你的UI线程连接,处理消息的代码就很在UI线程中执行