android Handler机制源码详解
来源:互联网 发布:打扮家 知乎 编辑:程序博客网 时间:2024/05/01 20:18
1、Handler介绍
Handler机制是android系统提供给我们的一种消息处理机制,最常见的应用就是在子线程更新UI操作。其实查看android源码可以发现,activity中所有的生命周期方法的回调都是应用的Handler机制。
Handler机制主要是为了解决安卓系统中多线程并发的问题,试想如果如果在没有加锁的情况下在多个子线程中更新主线程即UI线程界面,会造成界面错乱,我们也无法控制界面显示,如果在UI线程中加锁的话又会造成性能下降,影响用户体验。Google推出的Handler机制则不需要考虑这些问题,对UI界面的更新操作都会封装成一个个message轮询处理。
2、Message、Looper、MessageQueue
引用官方API中的描述:
我们平时在子线程中更新UI一般都是类似如下代码
private TextView textView; private Button bt_update; Handler mHandler = new Handler(){public void handleMessage(android.os.Message msg) {String str = (String) msg.obj;textView.setText(str);}; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView)findViewById(R.id.textview); bt_update = (Button)findViewById(R.id.bt_update); bt_update.setOnClickListener(this); } @Overridepublic void onClick(View v) { switch (v.getId()) {case R.id.bt_update:new Thread(){ public void run() { try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();} Message message = Message.obtain(); message.obj = "我更新了"; mHandler.sendMessage(message); }; }.start();break;default:break;}}整个过程大致如下:Message负责封装消息,Looper类负责轮询消息,相当于水泵,不停的调用下一个消息。MessageQueue是Looper的内部一个存放消息的消息队列。在handler调用sendMessage方法时会将message插入到MessageQueue中,然后调用Looper.loop()方法去轮询消息并调用handler的handleMessage方法。
3、Handler机制源码分析
我们首先查看一下Handler的构造方法:
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); } /** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */ public Handler(Callback callback) { this(callback, false); } /** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(Looper looper) { this(looper, null, false); } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */ public Handler(Looper looper, Callback callback) { this(looper, callback, false); } /** * Use the {@link Looper} for the current thread * 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 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(boolean async) { this(null, async); } /** * 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()); } } 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; } /** * 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 {@link MessageQueue#enqueueSyncBarrier(long)}. * * @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; }可以看出,前面的构造方法最终都调用到了最后两个,两个参数的和三个参数的,三个参数的要传入一个Looper。
我们看看最常用的无参的构造方法,它调用的是Handler(Callback callback, boolean async)这个构造方法。方法中开始即84-91行,检测Handler是否会引发内存泄漏,然后第93行调用了Looper.myLooper()并赋值给我们的成员变量mLooper,我们看一下这个方法
/** * 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(); }sThreadLocal是ThreadLocal的一个实例。ThreadLocal主要用来存储和当前线程相关联的对象,它会给每个使用ThreadLocal中变量的线程都保存一个副本,线程之间修改和使用该变量都是独立的,ThreadLocal常用的就是set和get方法。如果mLooper为空的话,就会抛出一个异常new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()")。这个异常什么时候会出现呢?当我们在子线程中new Handler()之前,如果没有调用Looper.prepare()时,就会抛出这个异常。那么我们看看这个Looper.prepare()究竟干了什么
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ 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)); }
原来只是新建了一个Looper对象并保存在sThreadLocal中,顺便我们可以看到,一个线程中只能创建一个Looper对象,如果调用过Looper.prepare()后再次调用就会抛出异常。
平时我们在主线程中创建Handler时并没有调用Looper.prepare(),这是因为android系统在启动的时候已经在主线程创建了一个Looper,同时还调用了Looper.loop()方法去不停的轮询处理消息。但是子线程并没有这些操作,所以子线程中我们创建Handler时就要这样操作
new Thread(){public void run() { Looper.prepare(); Handler handler = new Handler(){ public void handleMessage(Message msg) { //do something }; }; Looper.loop();};}.start();
Looper.loop()要和Looper.prepare()配套使用,否则handleMessage还是无法执行。我们来看看Looper.loop()方法做了什么
/** * 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 (;;) { 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); } 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.recycleUnchecked(); } }第6-9行判断当前线程的looper是否为空,为空的话会抛出异常。如果不为空的话就将当前looper的messagequeue对象放在一个无限for循环中去轮询处理,即17-49行代码。for循环中我们重点看31行,其中msg.target就是发送该条消息的handler,至于什么时候赋值的我们看看handler的sendMessage方法
/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }直接调用了sendMessageDelayed,我们继续看
/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }调用了sendMessageAtTime(),然后在其中判断mQueue是否为空,这个mQueue就是我们在Handler的构造方法中赋值的。如果mQueue不为空就会调用enqueueMessage,我们看看这个方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }原来在这里就将handler赋值给了msg.target,最后还调用queue.enqueueMessage将消息和时间都插入到MessageQueue中等待Looper轮询处理。ok,那么handler的handleMessage方法是什么时候调用的呢?我们返回到Looper.loop()方法中,我们看看for循环中的msg.target.dispatchMessage(msg)这句,这里我们已经知道msg.target就是对应的handler,我们看看handler的dispatchMessage()方法
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }首先判断message的callback是否为空,这个值我们一般没有赋值。如果为空的话就会判断mCallback是否为空,这个mCallback是什么赋值的呢?其实也是在创建handler的时候。如果我们创建handler的时候没有创建mCallback,就会直接执行handleMessage方法;否则就会执行mCallback的handleMessage方法,这个方法有个boolean型返回值,返回值为true时就不会执行handler自身的handleMessage方法,为false时就会执行自身的handleMessage方法。
至此整个流程也就结束。
4、更新UI的四种方式
第一种handler.post(Runnable r)
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ 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; }第二种view.post(Runnable action)
/** * <p>Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread.</p> * * @param action The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. * * @see #postDelayed * @see #removeCallbacks */ public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } // Assume that post will succeed later ViewRootImpl.getRunQueue().post(action); return true; }第三种runOnUiThread(Runnable action),这个方法是Activity中的方法
/** * Runs the specified action on the UI thread. If the current thread is the UI * thread, then the action is executed immediately. If the current thread is * not the UI thread, the action is posted to the event queue of the UI thread. * * @param action the action to run on the UI thread */ public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }
第四种不用说了,就是我们最常用的方式:handler.sendMessage(Message msg)
以上四种方式,其实查看源码发现最后都回归到了handler机制上,所以理解了handler机制就可以融会贯通了。
- android Handler机制源码详解
- 【Android】Handler机制源码详解(一)
- 【Android】Handler机制源码详解(二)
- Android源码剖析之-------Handler机制详解
- Android 源码解析(02) Handler机制详解
- android 详解Handler内部源码机制
- Android Handler机制详解
- Android Handler机制详解
- Android-Handler机制详解
- Handler机制和源码详解
- Android源码分析--Handler和Looper机制详解
- Android异步消息处理机制详解及源码分析 Handler
- Android源码分析--Handler和Looper机制详解
- Android源码分析--Handler和Looper机制详解
- Android Handler机制 源码解析
- Android Handler机制源码分析
- Android Handler机制源码解析
- android handler机制源码解析
- JS初级给页面添加6000个按钮
- 路由器端口映射实现外网访问本地服务器
- 算法-第四版-练习1.3.11解答
- 让Xcode8支持iPhone4
- 《C++ Primer Plus》2.7编程练习
- android Handler机制源码详解
- Python学习六之文件
- Elasticsearch 下载 安装
- linux系统下搭建mongodb环境
- Golang的并发处理
- Golang和HTTPS在网站前端接入里的高效应用
- 图解集合2:LinkedList
- Golang语言 之网络
- golang五周岁