- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
关系
Looper: 是一个消息轮训器,他有一个叫 loop() 的方法,用于启动一个循环,不停的去轮询消息池。
这里插一句,Looper 中的 loop() 方法是如何实现阻塞的呢?可查看 Android-Discuss issue 245
- MessageQueue:就是上面说到的消息池
- Handler:用于发送消息,和处理消息
- Message:一个消息对象
现在要问了,他们是怎么关联起来的?
一切都要从 Handler 的构造方法开始。如下所示
final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
可以看到 Handler 本身定义了一个 MessageQueue 对象 mQueue,和一个 Looper 的对象 mLooper。
不过,对 Handler 的这两个成员变量的初始化都是通过 Looper 来赋值的。
mLooper = Looper.myLooper(); mQueue = mLooper.mQueue;
现在,我们新建的 Handler 就和 Looper、MessageQueue 关联了起来,而且他们是一对一的关系,一个 Handler 对应一个 Looper,同时对应一个 MessageQueue 对象。这里给 MessageQueue 的赋值比较特殊,
mQueue = mLooper.mQueue;
这里直接使用 looper 的 mQueue 对象,将 looper 的 mQueue 赋值给了 Handler 自己,现在 Looper 和 Handler 持有着同一个 MessageQueue 。
这里可以看到 Looper 的重要性,现在 Handler 中的 Looper 实例和 MessageQueue 实例都是通过 Looper 来完成设置的,那么下面我们具体看看 Looper 是怎么实例化的,以及他的 mQueue 是怎么来的。
Looper
从上面 Handler 的构造方法中可以看到,Handler 的 mLooper 是这样被赋值的。
mLooper = Looper.myLooper();
接着看 myLooper() 的实现。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
这里出现了一个平时不怎么看到的 ThreadLocal 类,关于这个类,推荐去阅读任玉刚的一篇文章 - Android 的消息机制之 ThreadLocal 的工作原理,讲的很不错。另外自己也写了一篇文章,用于讲解 ThreadLocal 的用法,以及他在 Handler 和 Looper 中的巧妙意义。
任玉刚 - Android 的消息机制之 ThreadLocal 的工作原理
这里他是通过 ThreadLocal 的 get 方法获得,很奇怪,之前我们没有在任何地方对 sThreadLocal 执行过 set 操作。 这里却直接执行 get 操作,返回的结果必然为空啊!
但是如果现在为空,我们在 new Handler() 时,程序就已经挂掉了啊,因为在 Handler 的构造方法中,如果执行 Looper.myLooper() 的返回结果为空。
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }
但是,我们的程序没有挂掉,这意味着,我们在执行 myLooper() 方法时,他返回的结果不为空。
为什么呢?那我们在 Looper 中看看,哪里有对应的 set 方法,如下所示,我们找到了一个全局静态方法 prepare
public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
我们看到,在最后一行这里,执行了对应的 set 操作,这里把一个 new 出来的 Looper 直接 set 到 sThreadLocal 中。
但是我们不知道,到底什么时候,是谁调用了 prepare() 方法,从而给 sThreadLocal 设置了一个 Looper 对象。
后来在网上经过搜索,找到了答案,我们的 Android 应用在启动时,会执行到 ActivityThread 类的 main 方法,就和我们以前写的 java 控制台程序一样,其实 ActivityThread 的 main 方法就是一个应用启动的入口。
在这个入口里,会做很多初始化的操作。其中就有 Looper 相关的设置,代码如下
public static void main(String[] args) { //............. 无关代码............... Looper.prepareMainLooper(); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
在这里,我们很清楚的看到,程序启动时,首先执行 Looper.prepareMainLooper() 方法,接着执行了 loop() 方法。
先看看 prepareMainLooper 方法。
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
这里,首先调用了 prepare() 方法,执行完成后,sThreadLocal 成功绑定了一个 new Looper() 对象,然后执行
sMainLooper = myLooper();
可以看看 sMainLooper 的定义,以及 myLooper() 方法;
private static Looper sMainLooper; // guarded by Looper.class public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
现在的 sMainLooper 就有值了,也就是说,只要我们的 App 启动,sMainLooper 中就已经设置了一个 Looper 对象。以后调用 sMainLooper 的 get 方法将返回在程序启动时设置的 Looper,不会为空的。
下面在看 main 方法中的 调用的 Looper.loop() 方法。 已经把一些无关代码删了,否则太长了,
public static void loop() { //获得一个 Looper 对象 final Looper me = myLooper(); // 拿到 looper 对应的 mQueue 对象 final MessageQueue queue = me.mQueue; //死循环监听(如果没有消息变化,他不会工作的) 不断轮训 queue 中的 Message for (;;) { // 通过 queue 的 next 方法拿到一个 Message Message msg = queue.next(); // might block //空判断 if (msg == null)return; //消息分发 msg.target.dispatchMessage(msg); //回收操作 msg.recycleUnchecked(); } }
现在,想一个简单的过程,我们创建了一个 App,什么也不做,就是一个 HelloWorld 的 Android 应用, 此时,你启动程序,即使什么也不干,按照上面的代码,你应该知道的是,现在的程序中已经有一个 Looper 存在了。 并且还启动了消息轮询。 Looper.loop();
但是,目前来看,他们好像没什么用,只是存在而已。
此时你的项目如果使用了 Handler,你在主线程 new 这个 Handler 时,执行构造方法
public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
此时的 myLooper() 返回的 Looper 就是应用启动时的那个 Looper 对象,我们从 Looper 的构造方法得知,在 new Looper 时,会新建一个对应 的消息池对象 MessageQueue
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
那么在 Handler 的构造方法中,那个 mQueue 其实也是在应用启动时就已经创建好了。
现在再来回顾一下 Handler 的构造方法,在构造方法中,他为自己的 mQueue 和 mLooper 分别赋值,而这两个值其实在应用启动时,就已经初始化好了。
并且,现在已经启动了一个消息轮训,在监听 mQueue 中是不是有新的 Message ,现在这个轮训器已经好了,我们看发送消息的过程。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论