说到Handler想必你们都常常用到,在非UI线程更新UI那但是利器,用起来也很是容易上手android
从使用上来讲,咱们只须要关注sendMessage和handleMessage便可多线程
因此咱们先从Handler和Message来讲起,先看一小段代码ide
public static final int UPDATE_TEXT_VIEW = 0; public TextView mResultTextView = null; // new 一个 Handler 对象, 之内部类的方式重写 handleMessage 这个函数 public Handler mMyHandler = new Handler() { // ③ 处理消息 public void handleMessage(android.os.Message msg) { switch (msg.what) { case UPDATE_TEXT_VIEW: /* 这里可更新 ui */ mResultTextView.setText(String.valueOf(msg.arg1)); break; default: /* do nothing */ break; } }; }; // ================================================================== // 函数名: calc // 日期: 2015-08-30 // 功能: 计算入参并显示在 UI 上,而后后续以每秒 +1 在 UI 上更新 // 输入参数: int a // int b // 返回值: 无 // 修改记录:千里草新增函数 // ================================================================== public void calc(int a, int b) { int c = a + b; final Message msg = new Message(); msg.what = UPDATE_TEXT_VIEW; msg.arg1 = c; // ① 发送消息 mMyHandler.sendMessage(msg); // 这里更新 UI 线程的TextView OK // mResultTextView.setText(String.valueOf(msg.arg1)); // 启动一个新的线程来每秒刷新 TextView new Thread() { public void run() { while (true) { msg.arg1++; // ② 发送消息 mMyHandler.sendMessage(msg); // mResultTextView.setText(String.valueOf(msg.arg1)); 这里会报错 try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); }
代码中有①,②两处发送消息,. 分别是从UI线程和从子线程发送的消息, 在③处两个消息均可以被准确的接收到.函数
在接受消息函数handleMessage 里咱们能够作任何想作的事情,包括更新UI…oop
从使用来讲,你们根据这个例子,想必已经能够简单使用Handler来处理多线程之间的交互了…post
此处须要注意的是在使用Handler时,必须须要重写handleMessage 才能达到咱们想达到的目的...(从逻辑上来讲,没有接受消息的地方,发送的消息有何意义呢,是吧….从原理上..咱们接下来会谈到……)ui
谈到Handler,咱们还能够用它执行一个Runnable多线程…例以下面的代码..this
mMyHandler.post(new Runnable() { @Override public void run() { // 这里须要注意的是,calc 是在子线程里被调用,因此calc 就没法操做 UI 了. calc(1, 2); } });
Handler可真神奇,既能够发消息也能够执行某个任务线程.spa
为了更深层次的了解它,只能去看看它的源码了.let’s go!线程
先看看是如何post一个Runnable线程的
public final boolean post(Runnable r) { //这里其实是发送了一个Message return sendMessageDelayed(getPostMessage(r), 0); } //组装一个只带Runnable的Message private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } //发送消息 public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
哎哟喂,这Handler小丫头片子,还伪装两幅面孔呢, 经查看源码,发现它其实是发送了一个Message消息,然而这个消息仅仅携带了一个Runnable对象.
如今来看只须要分析Handler和Message了..咱们来看看最终Handler是如何发送消息的..咱们继续看源码,非得把他们扒个精光不可
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; //消息队列,这里存储Handler发送的消息 MessageQueue queue = mQueue; if (queue != null) { //Message与Handler绑定 msg.target = this; //消息进队列 sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
从消息最终被发出的函数来看,这里只作了两个事情:
1.Message与Handler绑定
2.将Message放进消息队列里
消息进队列以后,Handler发送消息的任务算是完美的完成了,接下来咱们该介绍介绍Looper了,若是没有Looper,Handler和Message之间的爱情能够说是不完整的.
咱们先来看看一个Looper是如何使用的吧
class LooperThread extends Thread { public Handler mHandler; public void run() { // 为当前线程准备一个 Looper Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // 处理消息 } }; // Looper 开始工做 Looper.loop(); } }
//继续看源码,prepare执行以后sThreadLocal绑定一个Looper对象 //sThreadLocal 能且只能绑定一个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)); } /** * 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; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); //无条件的for循环,来遍历Messagequeue for (;;) { //获取下一条消息 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } //Message绑定的Handler来开始处理消息.. 下面贴上dispatchMessage,函数,你们继续往下看 msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "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); } msg.recycle(); } } /** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ public interface Callback { public boolean handleMessage(Message msg); } /** * Subclasses must implement this to receive messages. * 子类必须完成handleMessage这个函数来接收消息 */ public void handleMessage(Message msg) { } /** * Handle system messages here. */ public void dispatchMessage(Message msg) { //收到消息后,先处理Runnable 对象callback. if (msg.callback != null) { handleCallback(msg); } else { //若是这里有回调接口,那么就直接调用该接口,再也不继续调用Handler的handleMessage函数来处理消息 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
从上述加了中文注释的代码中能看出,Handler发送的Message经过Looper分发给了各自的Handler.
因此上面说的在使用Handler时,必须须要重写handleMessage 才能达到咱们想达到的目的...也不彻底正确,
咱们也能够实现一个CallBack接口来处理消息,用Google的原话是
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ public interface Callback { public boolean handleMessage(Message msg); }
再贴最后一段代码来不折不扣说明Handler Looper之间的关系, 那就是Handler的 构造函数
/** * Default constructor associates this handler with the queue for the * current thread. * * If there isn't one, this handler won't be able to receive messages. */ public Handler() { 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(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //与当前线程的消息队列绑定 mQueue = mLooper.mQueue; mCallback = null; }
一句话总结来讲,Handler初始化时绑定了线程的MessageQueue,当前线程的Looper来依次分发MessageQueue里的消息.
MessageQueue的消息会根据Message的target绑定的Handler被Looper分发到各自的Handler里去处理.
例如Activity里有两个HandlerA和HandlerB, HandlerA发送的消息绝对不可能被HandlerB处理..
先暂时写到这里吧,后续补上流程图和类图
上述只是我的的很片面的理解,但愿你们补充和指出不足的地方…
2015年9月4日 04:10:05 千里草