//建立Binder通道 (创建新线程)
thread.attach(false);
Looper.loop(); //消息循环运行
throw new RuntimeException(“Main thread loop unexpectedly exited”);
}
Activity的生命周期都是依靠主线程的 Looper.loop
,当收到不同Message
时则采用相应措施:一旦退出消息循环,那么你的程序也就可以退出了。 从消息队列中取消息可能会阻塞,取到消息会做出相应的处理。如果某个消息处理时间过长,就可能会影响UI线程的刷新速率,造成卡顿的现象。
thread.attach(false)
方法函数中便会创建一个Binder线程(具体是指ApplicationThread
,Binder
的服务端,用于接收系统服务AMS
发送来的事件),该Binder线程通过Handler
将Message
发送给主线程。「Activity 启动过程」
比如收到msg=H.LAUNCH_ACTIVITY
,则调用ActivityThread.handleLaunchActivity()
方法,最终会通过反射机制,创建Activity
实例,然后再执行Activity.onCreate()
等方法;
再比如收到msg=H.PAUSE_ACTIVITY
,则调用ActivityThread.handlePauseActivity()
方法,最终会执行Activity.onPause()
等方法。
主线程的消息又是哪来的呢?当然是App进程中的其他线程通过Handler发送给主线程进程
3.ActivityThread 的动力是什么?
进程 每个app运行时前首先创建一个进程,该进程是由Zygote fork出来的,用于承载App上运行的各种Activity/Service
等组件。进程对于上层应用来说是完全透明的,这也是google有意为之,让App程序都是运行在Android Runtime
。大多数情况一个App就运行在一个进程中,除非在AndroidManifest.xml
中配置Android:process
属性,或通过native代码fork进程
线程 线程对应用来说非常常见,比如每次new Thread().start
都会创建一个新的线程。该线程与App所在进程之间资源共享,从Linux角度来说进程与线程除了是否共享资源外,并没有本质的区别,都是一个task_struct
结构体,在CPU看来进程或线程无非就是一段可执行的代码,CPU采用CFS调度算法,保证每个task都尽可能公平的享有CPU时间片。
其实承载ActivityThread
的主线程就是由Zygote fork而创建的进程。
4.Handler 是如何能够线程切换
其实看完上面我们大致也清楚线程间是共享资源的。所以Handler处理不同线程问题就只要注意异步情况即可。
这里再引申出Handler的一些小知识点。 Handler创建的时候会采用当前线程的Looper
来构造消息循环系统,Looper
在哪个线程创建,就跟哪个线程绑定,并且Handler是在他关联的Looper
对应的线程中处理消息的。(敲黑板)
那么Handler内部如何获取到当前线程的Looper
呢—–ThreadLocal
。ThreadLocal
可以在不同的线程中互不干扰的存储并提供数据,通过ThreadLocal
可以轻松获取每个线程的Looper
。
当然需要注意的是:
①线程是默认没有
Looper
的,如果需要使用Handler,就必须为线程创建Looper。我们经常提到的主线程,也叫UI线程,它就是ActivityThread
,
②ActivityThread
被创建时就会初始化Looper
,这也是在主线程中默认可以使用Handler的原因。