一、概念
1.1 主线程
一个线程总是由另一个线程启动,所以总有一条特殊的线程即主线程。
1.2 UI线程
APP启动时系统会为它创建一条执行线程即主线程,主线程用来处理所有与用户界面相关的操作(触摸、布局、绘制、动画)以及UI组件的声明周期(创建、销毁、更新),因此也称为UI线程。
1.3 子线程(工作线程)
多线程并发访问同一个资源会发生竞态条件或死锁问题,为了性能和稳定性 Android 将UI框架设计为单线程的时间队列模型(采用一个专门的线程从队列中抽取事件并将它们转发到应用程序定义的事件处理器),会在 ViewRootImpl 中调用 checkThread() 方法检测是否是在UI线程中更新UI。因此不要阻塞UI线程、不要在子线程中访问UI,会容易引发ANR(Application Not Response)异常。
1.3.1 不要阻塞UI线程
即不要在主线程中做耗时任务,同一进程中的所有组件都是在UI线程中实例化的,以下分别对应该组件中的线程被阻塞多少秒后会报ANR异常。
Activity | 5秒。 |
Broadcast | 前台10秒、后台60秒。 |
Service | 前台20秒、后台200秒。 |
ContentProvider | 10秒。 |
Input | 5秒。 |
1.3.2 不要在子线程中访问UI
由于不能阻塞主线程,可以使用子线程来做耗时操作(图片加载,网络请求等),由于不能在非UI线程上更新界面,可以使用以下几种方法来更新:
Activity | public final void runOnUiThread(Runnable action) |
Handler | public final boolean post(Runnable r) public final boolean postDelayed(Runnable r, long delayMillis) |
View | public boolean post(Runnable action) boolean postDelayed(Runnable action, long delayMillis) |
Kotlin Coroutine | 协程调度器指定Dispatcher.Main |
Thread {runOnUiThread {textView.text = ""}textView.post {textView.text = ""}Handler(Looper.getMainLooper()).post {textView.text = ""}CoroutineScope(Dispatchers.Main).launch {textView.text = ""}
}.start()