Handler 机制 源码 + 图 + 常见问题 + Demo 详细记录(本文内容略长, 但内容较为详细, 推荐 Android 开发者可深入观看. 如有问题, 欢迎指正)
Android 的消息处理有三个核心类: Looper,Handler 和 Message. 还有一个 MessageQueue(消息队列, 以下简称 MQ), 但是 MQ 被封装到 Looper 里面.
首先从 ActivityThread 类的 Main 函数开始:
- public static void main(String[] args) {
- ......// 篇幅问题, 内容已删减
- Looper.prepareMainLooper();
- // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
- // It will be in the format "seq=114"
- long startSeq = 0;
- if (args != null) {
- for (int i = args.length - 1; i>= 0; --i) {
- if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
- startSeq = Long.parseLong(
- args[i].substring(PROC_START_SEQ_IDENT.length()));
- }
- }
- }
- ActivityThread thread = new ActivityThread();
- thread.attach(false, startSeq);
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler();
- }
- ......// 篇幅问题, 内容已删减
- // End of event ActivityThreadMain.
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
ActivityThread main 函数中的第三行 Looper.prepareMainLooper(); 这里看下源码内容:
- /**
- * Initialize the current thread as a looper, marking it as an
- * application's main looper. The main looper for your application
- * is created by the Android environment, so you should never need
- * to call this function yourself. See also: {@link #prepare()}
- */
- public static void prepareMainLooper() {
- prepare(false);// 调用该方法在 ThreadLocal 中创建 Looper 对象
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
如上代码内容调用了 prepare(false); 方法. 这里我们分析下 handler 机制中 Looper 的作用.
01 一. Looper
Looper 的字面意思是 "循环者", 它被设计用来使一个普通线程变成 Looper 线程. 所谓 Looper 线程就是循环工作的线程. 在程序开发中(尤其是 GUI 开发中), 我们经常会需要一个线程不断循环, 一旦有新任务则执行, 执行完继续等待下一个任务, 这就是 Looper 线程. 使用 Looper 类创建 Looper 线程很简单:
- public class LooperThread extends Thread {
- @Override
- public void run() {
- // 将当前线程初始化为 Looper 线程
- Looper.prepare();
- // ... 其他处理, 如实例化 handler
- // 开始循环处理消息队列
- Looper.loop();
- }
- }
以上类似在 ActivityThread 中的使用. prepareMainLooper()中也是调用的 Looper.prepare(); 通过上面两行核心代码, 你的线程就升级为 Looper 线程了!!! 是不是很神奇? 让我们放慢镜头, 看看这两行代码各自做了什么.
1)Looper.prepare()
通过下图可以看到, 现在你的线程中有一个 Looper 对象, 它的内部维护了一个消息队列 MQ. 注意, 一个 Thread 只能有一个 Looper 对象
- public class Looper {
- // 每个线程中的 Looper 对象其实是一个 ThreadLocal, 即线程本地存储 (ThreadLocal) 对象
- private static final ThreadLocal sThreadLocal = new ThreadLocal();
- // Looper 内的消息队列
- final MessageQueue mQueue;
- // 当前线程
- Thread mThread;
- // ... 其他属性
- // 每个 Looper 对象中有它的消息队列, 和它所属的线程
- private Looper() {
- mQueue = new MessageQueue();
- mRun = true;
- mThread = Thread.currentThread();
- }
- // 我们调用该方法会在调用线程的 ThreadLocal 中创建 Looper 对象
- 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));
- }
- //ThreadActivity 中使用, 初始化 UI 线程为 Looper 线程
- public static void prepareMainLooper() {
- prepare(false);
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
- // 其他方法
- }
如果你还不清楚什么是 ThreadLocal, 请参考《多线程之 ThreadLocal 简析》
2)Looper.loop()
ActivityThread 中也调用了 Looper.loop() 1)中我们初始化先成为 Looper 线程. 使用 looper.loop()后 looper 线程就真的开始工作了. 它不断从自己的 MQ 中取出队头的消息 (也叫任务) 执行
- public static final void loop() {
- Looper me = myLooper(); // 得到当前线程 Looper
- MessageQueue queue = me.mQueue; // 得到当前 looper 的 MQ
- // 清除远程 Binder 调用端 uid 和 pid 信息, 并保存到 ident 变量
- Binder.clearCallingIdentity();
- final long ident = Binder.clearCallingIdentity();
- // 开始循环
- while (true) {
- Message msg = queue.next(); // 取出 message
- if (msg != null) {
- if (msg.target == null) {
- // message 没有 target 为结束信号, 退出循环
- return;
- }
- // 日志...
- if (me.mLogging!= null) me.mLogging.println(
- ">>>>> Dispatching to" + msg.target + " "
- + msg.callback + ":" + msg.what
- );
- // 非常重要! 将真正的处理工作交给 message 的 target, 即后面要讲的 handler
- msg.target.dispatchMessage(msg);
- // 还是日志...
- if (me.mLogging!= null) me.mLogging.println(
- "<<<<<Finished to" + msg.target + " "
- + msg.callback);
- // 清除远程 Binder 调用端 uid 和 pid 信息, 并保存到 newIdent 变量
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf("Looper", "Thread identity changed from 0x"
- + Long.toHexString(ident) + "to 0x"
- + Long.toHexString(newIdent) + "while dispatching to"
- + msg.target.getClass().getName() + " "
- + msg.callback + "what=" + msg.what);
- }
- // 回收 message 资源
- msg.recycle();
- }
- }
- }
这里我们看到, mLooper()方法里我们取出了当前线程的 looper 对象, 然后从 looper 对象开启了一个死循环
不断地从 looper 内的 MessageQueue 中取出 Message, 只要有 Message 对象, 就会通过 Message 的 target 调用
dispatchMessage 去分发消息, 通过代码可以看出 target 就是我们创建的 handler.Message 的分发调用 dispatchMessage(msg)方法, 接下分析 Handler 中我们会提到.
除了 prepare()和 loop()方法, Looper 类还提供了一些有用的方法
- //Looper.myLooper()得到当前线程 looper 对象
- public static final Looper myLooper() {
- // 在任意线程调用 Looper.myLooper()返回的都是那个线程的 looper
- return (Looper)sThreadLocal.get();
- }
- //getThread()得到 looper 对象所属线程
- public Thread getThread() {
- return mThread;
- }
- //quit()方法结束 looper 循环
- public void quit() {
- // 创建一个空的 message, 它的 target 为 NULL, 表示结束循环消息
- Message msg = Message.obtain();
- // 发出消息
- mQueue.enqueueMessage(msg, 0);
- }
上述的注释写的很清楚,
Looper 总结:
每个线程有且最多只能有一个 Looper 对象, 它是一个 ThreadLocal 对象
Looper 内部有一个消息队列, loop()方法调用后线程开始不断从队列中取出消息执行
Looper 使一个线程变成 Looper 线程.
大家可能注意到 Looper.loop()方法中第 22 行 msg.target.dispatchMessage(msg); 上文中的注释提到是用于消息分发, 处理 Message. 如何向往 MQ 上添加消息和处理消息是 Handler 的职责. 下面介绍异步大师 handler
02 二. Handler
什么是 handler? 简单来说: handler 扮演了往 MQ 上添加消息和处理消息的角色(只处理由自己发出的消息), 即通知 MQ 它要执行一个任务(sendMessage), 并在 loop 到自己的时候执行该任务(handleMessage), 整个过程是异步的. handler 创建时会关联一个 looper, 默认的构造方法将关联当前线程的 looper, 不过这也是可以 set 的. 构造方法如下:
- public class handler {
- final MessageQueue mQueue; // 关联的 MQ
- final Looper mLooper; // 关联的 looper
- final Callback mCallback;
- // 其他属性
- public Handler() {
- this(null, false);
- }
- public Handler(Callback callback) {
- this(callback, false);
- }
- public Handler(Looper looper) {
- this(looper, null, false);
- }
- public Handler(Looper looper, Callback callback) {
- this(looper, callback, false);
- }
- /**
- * Use the {@link Looper} for the current thread with the specified callback interface
- * and set whether the handler should be asynchronous.
- *
- * Handlers are synchronous by default unless this constructor is used to make
- * one that is strictly asynchronous.
- *
- * Asynchronous messages represent interrupts or events that do not require global ordering
- * with respect to synchronous messages. Asynchronous messages are not subject to
- * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
- *
- * @param callback The callback interface in which to handle messages, or null.
- * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
- * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
- *
- * @hide
- */
- 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());
- }
- }
- // 默认将关联当前线程的 looper
- mLooper = Looper.myLooper();
- // looper 不能为空, 即该默认的构造方法只能在 looper 线程中使用
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread " + Thread.currentThread()
- + "that has not called Looper.prepare()");
- }
- // 重要!!! 直接把关联 looper 的 MQ 作为自己的 MQ, 因此它的消息将发送到关联 looper 的 MQ 上
- mQueue = mLooper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
- /**
- * Use the provided {@link Looper} instead of the default one and take a callback
- * interface in which to handle messages. Also set whether the handler
- * should be asynchronous.
- *
- * Handlers are synchronous by default unless this constructor is used to make
- * one that is strictly asynchronous.
- *
- * Asynchronous messages represent interrupts or events that do not require global ordering
- * with respect to synchronous messages. Asynchronous messages are not subject to
- * the synchronization barriers introduced by conditions such as display vsync.
- *
- * @param looper The looper, must not be null.
- * @param callback The callback interface in which to handle messages, or null.
- * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
- * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
- *
- * @hide
- */
- public Handler(Looper looper, Callback callback, boolean async) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
- }
Handler 提供了多种构造方法, 默认的构造方法中 Looper 默认关联当前线程, 把关联 Looper 的 MQ 作为自己的 MQ. 三个参数的构造方法中需要传入 Looper 对象, Callback 接口(这里简要提下)
- /**
- * Callback interface you can use when instantiating a Handler to avoid
- * having to implement your own subclass of Handler.
- */
- // 意思大概就是使用这个接口可以避免自己去写一个 Handler 的子类
- public interface Callback {
- /**
- * @param msg A {@link Android.os.Message Message} object
- * @return True if no further handling is desired
- */
- public boolean handleMessage(Message msg);
- }
在使用 Handler 时如果直接使用匿名内部类的方式创建 Handler 对象 ide 会发出警告, 提示内存泄漏风险. 这时可以通过创建继承 Handler 的静态内部类或使用弱引用来避免 Handler 对象持有外部类对象的强引用. 但是官方还提供了一个 Handler.Callback 接口.
注意: handler 会持有匿名对象的引用, 匿名对象会持有外部类对象的引用, 虽然 ide 不再警告但是内存泄漏问题并没有解决. 所以要在 onDestroy 方法中调用 handler.removeCallbacksAndMessages(null); 来清空消息. 或者用弱引用, 如下所示, 具体使用可见 Demo:
- Handler handler = new Handler(new WeakReference<Handler.Callback>(new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- return false;
- }
- }).get());
接下来继续 Handler, 我们把一)中的 Looper 线程加入 Handler
- public class LooperThread extends Thread {
- private Handler handler1;
- private Handler handler2;
- @Override
- public void run() {
- // 将当前线程初始化为 Looper 线程
- Looper.prepare();
- // 实例化两个 handler
- handler1 = new Handler();
- handler2 = new Handler();
- // 开始循环处理消息队列
- Looper.loop();
- }
- }
加入 handler 后的效果如下图:
可以看到, 一个线程可以有多个 Handler, 但是只能有一个 Looper(ThreadLocal 对象)!
Handler 发送消息
有了 handler 之后, 我们就可以使用 post(Runnable), postAtTime(Runnable, long),postDelayed(Runnable,long), sendEmptyMessage(int), sendMessage(Message),sendMessageAtTime(Message,long)和 sendMessageDelayed(Message, long)这些方法向 MQ 上发送消息了. 光看这些 API 你可能会觉得 handler 能发两种消息, 一种是 Runnable 对象, 一种是 message 对象, 这是直观的理解, 但其实 post 发出的 Runnable 对象最后都被封装成 message 对象了, 见源码:
- // 此方法用于向关联的 MQ 上发送 Runnable 对象, 它的 run 方法将在 handler 关联的 looper 线程中执行
- public final boolean post(Runnable r)
- {
- // 注意 getPostMessage(r)将 runnable 封装成 message
- return sendMessageDelayed(getPostMessage(r), 0);
- }
- private final Message getPostMessage(Runnable r) {
- Message m = Message.obtain(); // 得到空的 message
- m.callback = r; // 将 runnable 设为 message 的 callback,
- return m;
- }
- public boolean sendMessageAtTime(Message msg, long uptimeMillis)
- {
- boolean sent = false;
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this; // message 的 target 必须设为该 handler!
- sent = queue.enqueueMessage(msg, uptimeMillis);
- }
- else {
- RuntimeException e = new RuntimeException(
- this + "sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }
其他方法就不罗列了, 总之通过 handler 发出的 message 有如下特点:
1.message.target 为该 handler 对象, 这确保了 looper 执行到该 message 时能找到处理它的 handler, 即 loop()方法中的关键代码, 即上文中提到的 Message 分发:
msg.target.dispatchMessage(msg);
2.post 发出的 message, 其 callback 为 Runnable 对象
Handler 处理消息
说完了消息的发送, 再来看下 handler 如何处理消息. 消息的处理是通过核心方法 ( msg) 与钩子方法 ( msg) 完成的, 见源码:
- // 处理消息, 该方法由 looper 调用
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- // 如果 message 设置了 callback, 即 runnable 消息, 处理 callback!
- handleCallback(msg);
- } else {
- // 如果 handler 本身设置了 callback, 则执行 callback
- if (mCallback != null) {
- /* 这种方法允许让 activity 等来实现 Handler.Callback 接口, 避免了自己编写 handler 重写 handleMessage 方法. 见 http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- // 如果 message 没有 callback, 则调用 handler 的钩子方法 handleMessage
- handleMessage(msg);
- }
- }
- // 处理 runnable 消息
- private final void handleCallback(Message message) {
- message.callback.run(); // 直接调用 run 方法!
- }
- // 由子类实现的钩子方法
- public void handleMessage(Message msg) {
dispatchMessage(Message msg)方法为 Public 提供给 Looper 进行消息传递, 这里一般情况下不需要重写, 目前也没见到过重写场景, 如有, 请指教...
可以看到, 除了 ( msg) 和 Runnable 对象的 run 方法由开发者实现外(实现具体逻辑),handler 的内部工作机制对开发者是透明的. 这正是 handler API 设计的精妙之处!
Handler 的用处
Android 异步任务处理大师 Handler 拥有下面两个重要的特点:
1. handler 可以在任意线程发送消息, 这些消息会被添加到关联的 MQ 上.
2. handler 是在它关联的 looper 线程中处理消息的.
这就解决了 Android 最经典的不能在其他非主线程中更新 UI 的问题. Android 的主线程也是一个 looper 线程(looper 在 Android 中运用很广), 我们在其中创建的 handler 默认将关联主线程 MQ. 因此, 利用 handler 的一个 solution 就是在 activity 中创建 handler 并将其引用传递给 worker thread,worker thread 执行完任务后使用 handler 发送消息通知 activity 更新 UI.(过程如图)
具体 Demo 及 Handler 使用方法请移步: GitHub(同性交友社区):
https://github.com/AnyMarvel/HandlerDemo
WorkDemo Activity 工作内容如下:
- public class HandlerWorkDemo extends AppCompatActivity {
- TextView textView;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.handler_work);
- textView = findViewById(R.id.workText);
- // 创建并启动工作线程
- Thread workerThread = new Thread(new SampleTask(new MyHandler()));
- workerThread.start();
- }
- public void appendText(String msg) {
- textView.setText(textView.getText() + "\n" + msg);
- }
- // 内部类, 实现 MyHandler
- class MyHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- String result = msg.getData().getString("message");
- // 更新 UI
- appendText(result);
- }
- }
- private class SampleTask implements Runnable {
- private Handler handler;
- public SampleTask(MyHandler myHandler) {
- this.handler = myHandler;
- }
- @Override
- public void run() {
- try { // 模拟执行某项任务, 下载等
- Thread.sleep(5000);
- // 任务完成后通知 activity 更新 UI
- Message msg = prepareMessage("task completed!");
- // message 将被添加到主线程的 MQ 中
- handler.sendMessage(msg);
- } catch (InterruptedException e) {
- Log.d("SampleTask", "interrupted!");
- }
- }
- private Message prepareMessage(String str) {
- Message result = handler.obtainMessage();
- Bundle data = new Bundle();
- data.putString("message", str);
- result.setData(data);
- return result;
- }
- }
- }
当然, handler 能做的远远不仅如此, 由于它能 post Runnable 对象, 它还能与 Looper 配合实现经典的 Pipeline Thread(流水线线程)模式. Handler 作为 Android 异步任务大师, 还有一些比较经典的用法, 这里不再一一赘述, 有遇到 handler 坑的欢迎留言
03 三 .Message
对于稍有经验的开发人员来说我们在使用 Handler 发送异步消息获取 Message 的时候都会使用如下代码获取一个 Message 对象:
Message msg = mHandler.obtainMessage();
而不是直接 new 一个:
Message msg = new Message();
二者的主要区别就是上面的用到缓存池概念, 如果池中有闲着的则拿来用, 没有则 new 一个 Message. 后者则没有这个机制, 直接 new 一个拿来用.
接下来我们分析一下这个缓存池是怎么实现的.
Message 缓存池源码分析
Handler 中 obtainMessage()方法实质还是调用的 Message 中 obtain()方法, 这里就直接看 Message 中 obtain()方法源码了:
- // 锁对象, 只读不写, final 修饰
- public static final Object sPoolSync = new Object();
- private static Message sPool;
- private static int sPoolSize = 0;
- private static final int MAX_POOL_SIZE = 50;
- private static boolean gCheckRecycle = true;
- /**
- * Return a new Message instance from the global pool. Allows us to
- * avoid allocating new objects in many cases.
- */
- public static Message obtain() {
- synchronized (sPoolSync) {
- // 判断 sPool 是否为空, 为空则 New Message 对象, 不为空则获取缓存中的 Message 对象
- if (sPool != null) {
- // 单链表的结构, 将 sPool 指向当前 Message,Message 的 next 指向下一个 Message.
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- m.flags = 0; // clear in-use flag
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
代码很简单, 给 sPoolSync 加锁后, 判断 sPool 是否为 null, 不为 null 则将 sPool 引用指向一个新的 Message, 并将新的 Message 的 next 的引用指向 sPool, 随即将 next 置空, 标记重置, sPoolSize--, 返回一个 Message; 如果 sPool 为 null 的话, 直接 new 出一个 Message.
obtain()主要逻辑就是先判断缓存池中是否存在空闲 message, 如果存在则返回头部 message, 并且指针指向下一个空闲 message, 然后头部的 message 与之后链表 断开连接. 如果不存在空闲 message 则直接 new 一个直接返回.
上面的逻辑都是从缓存池中获取的操作, 那什么时候向缓存池中存放呢? 我们继续向下分析.
Message 类中 recycle()方法是用于回收用完的 mesage, 将此 message 会收到缓存池中, 是这样的吗? 我们看下源码就知道了:
- public void recycle() {
- if (isInUse()) {
- if (gCheckRecycle) {
- throw new IllegalStateException("This message cannot be recycled because it"
- + "is still in use.");
- }
- return;
- }
- recycleUnchecked();
- }
recycle 方法中主要判断当前 message 是否正在使用中, 如果正在使用则抛出异常, 没被使用则调用 recycleUnchecked()方法, 接下来看下 recycleUnchecked():
- /**
- * Recycles a Message that may be in-use.
- * Used internally by the MessageQueue and Looper when disposing of queued Messages.
- */
- void recycleUnchecked() {
- // Mark the message as in use while it remains in the recycled object pool.
- // Clear out all other details.
- flags = FLAG_IN_USE;
- what =0 ;
- arg1 =0 ;
- arg2 =0 ;
- obj = null;
- replyTo = null;
- sendingUid = -1;
- when =0 ;
- target = null;
- callback = null;
- data = null;
- synchronized (sPoolSync) {
- if (sPoolSize <MAX_POOL_SIZE) {
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
判断当前缓存池 sPoolSize 是否小于设定的最大缓冲池大小, 如果小于这个值, 则将 sPool 指向下一个 Message, 当前 Message 指向 sPool,sPoolSize++, 相当于回收了这个使用过的 Message.
message 的用法比较简单, 这里不做总结了, 但需要注意以下几点:
1. 尽管 Message 有 public 的默认构造方法, 但是你应该通过 Message.obtain()来从消息池中获得空消息对象, 以节省资源.
2. 如果你的 message 只需要携带简单的 int 信息, 请优先使用 Message.arg1 和 Message.arg2 来传递信息, 这比用 Bundle 更省内存
3. 擅用 message.what 来标识信息, 以便用不同方式处理 message.
<svg width="360" height="32" xmlns="http://www.w3.org/2000/svg" style="box-sizing: border-box;"><text width="300" font-family="microsoft yahei" font-size="18" y="24" x="147.882" style="box-sizing: border-box;"><tspan class="135brush" data-brushtype="text" style="box-sizing: border-box;">恭喜看到这里, 完事了</tspan></text></svg>
总结:
一. Android Handler 使用流程
1. 判断当前线程是否为 Looper 线程, 否则初始化为 looper 线程
2. 初始化 handler
3. 基于 handler 发送消息
4. 基于 handler 处理消息
以上步骤看着很是简单, 但还是出现了各种问题
二. 注意事项总结
Handler 对象与其调用者在同一线程中, 如果在 Handler 中设置了延时操作, 则调用线程也会堵塞. 每个 Handler 对象都会绑定一个 Looper 对象, 每个 Looper 对象对应一个消息队列(MQ). 如果在创建 Handler 时不指定与其绑定的 Looper 对象, 系统默认会将当前线程的 Looper 绑定到该 Handler 上.
2. 在主线程中, 可以直接使用 new Handler()创建 Handler 对象, 其将自动与主线程的 Looper 对象绑定; 在非主线程中直接这样创建 Handler 则会报错, 因为 Android 系统默认情况下非主线程中没有开启 Looper, 而 Handler 对象必须绑定 Looper 对象. 这种情况下, 需先在该线程中手动开启 Looper(Looper.prepare()-->Looper.loop()), 然后将其绑定到 Handler 对象上; 或者通过 Looper.getMainLooper(), 获得主线程的 Looper, 将其绑定到此 Handler 对象上.
3.Handler 发送的消息都会加入到 Looper 的 MessageQueue 中. 一说 Handler 包含两个队列: 线程队列和消息队列; 使用 Handler.post()可以将线程对象加入到线程队列中; 使用 Handler.sendMessage()可以将消息对象加入到消息队列中. 通过源码分析证实, Handler 只有一个消息队列, 即 MessageQueue. 通过 post()传进去的线程对象将会被封装成消息对象后传入 MessageQueue.
4. 使用 post()将线程对象放到消息队列中后, 当 Looper 轮询到该线程执行时, 实际上并不会单独开启一个新线程, 而仍然在当前 Looper 绑定的线程中执行, Handler 只是调用了该线程对象的 run()而已. 如, 在子线程中定义了更新 UI 的指令, 若直接开启将该线程执行, 则会报错; 而通过 post()将其加入到主线程的 Looper 中并执行, 就可以实现 UI 的更新.
5. 使用 sendMessage()将消息对象加入到消息队列后, 当 Looper 轮询到该消息时, 就会调用 Handler 的 handleMessage()来对其进行处理. 再以更新 UI 为例, 使用这种方法的话, 就先将主线程的 Looper 绑定在 Handler 对象上, 重载 handleMessage()来处理 UI 更新, 然后向其发送消息就可以了.
(完)以上是对 Android Handler 机制的总结,(Handler 使用过程中容易造成内容溢出的问题这里没有做说明, demo 中有解决方法, 详情见 demo, 持续更新 handler 触发问题)
具体 Demo 及 Handler 使用方法请移步: GitHub(同性交友社区):
https://github.com/AnyMarvel/HandlerDemo
听说转发文章
会给你带来好运
PS: 搞了好久又把 Handler 机制给过了一遍, 觉的还不错的朋友给个赞呗
图片来自网络
公众号 求关注
来源: http://www.jianshu.com/p/cdfb75eb6f64