关于 Android 异步消息处理机制 Handler
2016-04-29 02:24
639 查看
详细的介绍可以看洋神的 Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系,我在这里只是简单的回顾一下。
Looper.prepare() 创建线程相关的 Looper 和 MessageQueue,Handler 将消息放入 MessageQueue,Looper.loop() 循环读取 Message 并交由 Handler 进行处理。
比较简单的用法:
调用 Looper.prepare() 来初始化 Looper
创建 Handler,通过 handleMessage 来处理消息
启动消息循环 Looper.loop()
然后就可以通过 mHandler 来向该线程发送消息了,也就实现了线程间的消息传递。下面来简单走读一下源码。
Looper 主要方法就这几个,构造方法是私有的,提供了静态方法供我们创建实例。从 Looper.prepare 可以看到有初始化 Looper,并将其放入了 ThreadLocal,且保证一个线程只能持有一个 Looper。MessageQueue 是在 Looper 构造方法里创建的,所以是一对一绑定的。
prepareMainLooper 也是初始化 Looper 的,只是它比较特殊,创建的是 UI 线程的 Looper,并且不需要我们手动调用,这也就是为什么在 UI 线程不需要再初始化 Looper 了。通过 Android Studio 的 Find Usages [option + F7]功能可以轻松找到 ActivityThread.main()方法里初始化了 MainLooper。
Looper.loop() 的作用是是启动消息循环,分发 msg
从代码上看也比较容易理解,从消息队列中获取消息,然后通过 msg.target.dispatchMessage(msg) 分发处理,留下的问题就是
msg 怎么进入的 MessageQueue
msg.target 是谁
可以看到 Handler 默认关联当前线程的 Looper,当然也可以指定其他 Looper。
当通过 Handler.sendMessage 发送消息时,最后调用了 enqueueMessage
可以看到 msg.target = this,也就是当前的 Handler,而 Looper.loop 中分发消息的时候 msg.target.dispatchMessage(msg) 也就将消息交回了 Handler 进行处理。
带 callback 的 msg , 直接调用了 run
mCallback != null, 也就是通过非空构造方法创建的 Handler
继承 Handler 的子类实现的 handleMessage 方法
这是一种常用的给 UI 线程发消息的方式
代码也非常好理解,在 UI 线程的话直接调用 run 方法,非 UI 线程则 postMessage,对应 Handler.dispatchMessage 的第一种处理方法,还是直接调用 run 方法。
一图胜千言
Looper.prepare() 创建线程相关的 Looper 和 MessageQueue,Handler 将消息放入 MessageQueue,Looper.loop() 循环读取 Message 并交由 Handler 进行处理。
Handler 的基本用法
从 Looper 的文档上可以看到最通常的用法class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
比较简单的用法:
调用 Looper.prepare() 来初始化 Looper
创建 Handler,通过 handleMessage 来处理消息
启动消息循环 Looper.loop()
然后就可以通过 mHandler 来向该线程发送消息了,也就实现了线程间的消息传递。下面来简单走读一下源码。
Looper
public final class Looper { // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; 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)); } public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /** * Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); } ...
Looper 主要方法就这几个,构造方法是私有的,提供了静态方法供我们创建实例。从 Looper.prepare 可以看到有初始化 Looper,并将其放入了 ThreadLocal,且保证一个线程只能持有一个 Looper。MessageQueue 是在 Looper 构造方法里创建的,所以是一对一绑定的。
prepareMainLooper 也是初始化 Looper 的,只是它比较特殊,创建的是 UI 线程的 Looper,并且不需要我们手动调用,这也就是为什么在 UI 线程不需要再初始化 Looper 了。通过 Android Studio 的 Find Usages [option + F7]功能可以轻松找到 ActivityThread.main()方法里初始化了 MainLooper。
Looper.prepareMainLooper(); ... if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop();
Looper.loop() 的作用是是启动消息循环,分发 msg
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } msg.target.dispatchMessage(msg); ... } }
从代码上看也比较容易理解,从消息队列中获取消息,然后通过 msg.target.dispatchMessage(msg) 分发处理,留下的问题就是
msg 怎么进入的 MessageQueue
msg.target 是谁
Handler
一般情况下我们是通过Handler handler = new Handler()来创建 Handler,其调用了有参的构造方法
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } 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 默认关联当前线程的 Looper,当然也可以指定其他 Looper。
当通过 Handler.sendMessage 发送消息时,最后调用了 enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
可以看到 msg.target = this,也就是当前的 Handler,而 Looper.loop 中分发消息的时候 msg.target.dispatchMessage(msg) 也就将消息交回了 Handler 进行处理。
最终 Message 分发的方式
Handler.dispatchMessagepublic void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } private static void handleCallback(Message message) { message.callback.run(); }
带 callback 的 msg , 直接调用了 run
mCallback != null, 也就是通过非空构造方法创建的 Handler
继承 Handler 的子类实现的 handleMessage 方法
Activity.runOnUiThread
runOnUiThread(new Runnable() { @Override public void run() { // } });
这是一种常用的给 UI 线程发消息的方式
public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } } public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
代码也非常好理解,在 UI 线程的话直接调用 run 方法,非 UI 线程则 postMessage,对应 Handler.dispatchMessage 的第一种处理方法,还是直接调用 run 方法。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories