Android Handler机制分析
2016-05-13 16:49
375 查看
今天特地分析了一下Handler机制原理,如何实现线程之间的通信的,最终总结了一下几个方面。
在主要有四个类:Handler、MessageQueue、Message、Looper
先看看基本的代码:
这是一个handler循环,每十秒钟会执行一次,不断的去更新数据,现在就看看这里是怎么工作的了,执行myHanler.sendEmptyMessageDelayed(0,10000)向主线程发送消息,Handler类有这个方法:
源代码里会根据内容生成一个Message对象,Message用于存放传递的内容,我们看看Message这个类:
这是一个序列化的类,handler和intent传递消息都是需要序列化的数据来完成。接着回到Handler类里面,继续执行会执行到这个方法:
这里MessageQueue就出现了,会把Message对象放入一个MessageQueue队列中,我们进入MessageQueue这个类里面:
这是一个同步的方法,会把Message对象放入MessageQueue里面。下面问题来了,Handler的handlerMessage什么时候会执行,我们看看HandlerMessage这个方法:
Handler类提供了一个Callback接口和handlerMessage方法,Handler类里还有dispatchMessage方法,调用了Callback接口和handlerMessage:
但是dispatchMessage方法什么时候调用,我们就找到了Looper这个类了,这个类里有方法loop(),看看这个方法里的内容:
那么问题又来了,Looper.loop()又啥时候会被调用,这个我们就找到了ActivityThread这个类(这个类在编辑器查看是被隐藏的,需要从浏览器中去查找Android源代码查看,这里我的查看地址:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/app/ActivityThread.java?av=fActivityThread向了解的可以自己去搜索一下,其实就是我们的UI线程,所以loop方法是在主线程中运行的),ActivityThread类里main函数里有这样的代码:
这里就会启动loop(),在for (;;) 执行。这里就通过源码分析了整个流程,Handler机制原理
在主要有四个类:Handler、MessageQueue、Message、Looper
先看看基本的代码:
Handler myHandler = new Handler() { public void handleMessage(Message msg) { if (!isStop) { getData(); myHandler.sendEmptyMessageDelayed(0, 10000); } } };
这是一个handler循环,每十秒钟会执行一次,不断的去更新数据,现在就看看这里是怎么工作的了,执行myHanler.sendEmptyMessageDelayed(0,10000)向主线程发送消息,Handler类有这个方法:
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }
源代码里会根据内容生成一个Message对象,Message用于存放传递的内容,我们看看Message这个类:
public final class Message implements Parcelable { /** * User-defined message code so that the recipient can identify * what this message is about. Each {@link Handler} has its own name-space * for message codes, so you do not need to worry about yours conflicting * with other handlers. */ public int what; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg1; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg2; /** * An arbitrary object to send to the recipient. When using * {@link Messenger} to send the message across processes this can only * be non-null if it contains a Parcelable of a framework class (not one * implemented by the application). For other data transfer use * {@link #setData}. * * <p>Note that Parcelable objects here are not supported prior to * the {@link android.os.Build.VERSION_CODES#FROYO} release. */ public Object obj; /** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */ public Messenger replyTo; /** * Optional field indicating the uid that sent the message. This is * only valid for messages posted by a {@link Messenger}; otherwise, * it will be -1. */ public int sendingUid = -1; /** If set message is in use. * This flag is set when the message is enqueued and remains set while it * is delivered and afterwards when it is recycled. The flag is only cleared * when a new message is created or obtained since that is the only time that * applications are allowed to modify the contents of the message. * * It is an error to attempt to enqueue or recycle a message that is already in use. */ /*package*/ static final int FLAG_IN_USE = 1 << 0; /** If set message is asynchronous */ /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /** Flags to clear in the copyFrom method */ /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next; private 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) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } /** * Same as {@link #obtain()}, but copies the values of an existing * message (including its target) into the new one. * @param orig Original message to copy. * @return A Message object from the global pool. */ public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; m.sendingUid = orig.sendingUid; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; } /** * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned. * @param h Handler to assign to the returned Message object's <em>target</em> member. * @return A Message object from the global pool. */ public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } /** * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on * the Message that is returned. * @param h Handler to assign to the returned Message object's <em>target</em> member. * @param callback Runnable that will execute when the message is handled. * @return A Message object from the global pool. */ public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; } /** * Same as {@link #obtain()}, but sets the values for both <em>target</em> and * <em>what</em> members on the Message. * @param h Value to assign to the <em>target</em> member. * @param what Value to assign to the <em>what</em> member. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what) { Message m = obtain(); m.target = h; m.what = what; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em> * members. * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param obj The <em>object</em> method to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.obj = obj; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, * <em>arg1</em>, and <em>arg2</em> members. * * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param arg1 The <em>arg1</em> value to set. * @param arg2 The <em>arg2</em> value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members. * * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param arg1 The <em>arg1</em> value to set. * @param arg2 The <em>arg2</em> value to set. * @param obj The <em>obj</em> value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; m.obj = obj; return m; } /** @hide */ public static void updateCheckRecycle(int targetSdkVersion) { if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) { gCheckRecycle = false; } } /** * Return a Message instance to the global pool. * <p> * You MUST NOT touch the Message after calling this function because it has * effectively been freed. It is an error to recycle a message that is currently * enqueued or that is in the process of being delivered to a Handler. * </p> */ public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } 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++; } } } /** * Make this message like o. Performs a shallow copy of the data field. * Does not copy the linked list fields, nor the timestamp or * target/callback of the original message. */ public void copyFrom(Message o) { this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM; this.what = o.what; this.arg1 = o.arg1; this.arg2 = o.arg2; this.obj = o.obj; this.replyTo = o.replyTo; this.sendingUid = o.sendingUid; if (o.data != null) { this.data = (Bundle) o.data.clone(); } else { this.data = null; } } /** * Return the targeted delivery time of this message, in milliseconds. */ public long getWhen() { return when; } public void setTarget(Handler target) { this.target = target; } /** * Retrieve the a {@link android.os.Handler Handler} implementation that * will receive this message. The object must implement * {@link android.os.Handler#handleMessage(android.os.Message) * Handler.handleMessage()}. Each Handler has its own name-space for * message codes, so you do not need to * worry about yours conflicting with other handlers. */ public Handler getTarget() { return target; } /** * Retrieve callback object that will execute when this message is handled. * This object must implement Runnable. This is called by * the <em>target</em> {@link Handler} that is receiving this Message to * dispatch it. If * not set, the message will be dispatched to the receiving Handler's * {@link Handler#handleMessage(Message Handler.handleMessage())}. */ public Runnable getCallback() { return callback; } /** * Obtains a Bundle of arbitrary data associated with this * event, lazily creating it if necessary. Set this value by calling * {@link #setData(Bundle)}. Note that when transferring data across * processes via {@link Messenger}, you will need to set your ClassLoader * on the Bundle via {@link Bundle#setClassLoader(ClassLoader) * Bundle.setClassLoader()} so that it can instantiate your objects when * you retrieve them. * @see #peekData() * @see #setData(Bundle) */ public Bundle getData() { if (data == null) { data = new Bundle(); } return data; } /** * Like getData(), but does not lazily create the Bundle. A null * is returned if the Bundle does not already exist. See * {@link #getData} for further information on this. * @see #getData() * @see #setData(Bundle) */ public Bundle peekData() { return data; } /** * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */ public void setData(Bundle data) { this.data = data; } /** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */ public void sendToTarget() { target.sendMessage(this); } /** * Returns true if the message is asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @return True if the message is asynchronous. * * @see #setAsynchronous(boolean) * @see MessageQueue#enqueueSyncBarrier(long) * @see MessageQueue#removeSyncBarrier(int) * * @hide */ public boolean isAsynchronous() { return (flags & FLAG_ASYNCHRONOUS) != 0; } /** * Sets whether the message is asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async True if the message is asynchronous. * * @see #isAsynchronous() * @see MessageQueue#enqueueSyncBarrier(long) * @see MessageQueue#removeSyncBarrier(int) * * @hide */ public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; } } /*package*/ boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE); } /*package*/ void markInUse() { flags |= FLAG_IN_USE; } /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}). */ public Message() { } @Override public String toString() { return toString(SystemClock.uptimeMillis()); } String toString(long now) { StringBuilder b = new StringBuilder(); b.append("{ when="); TimeUtils.formatDuration(when - now, b); if (target != null) { if (callback != null) { b.append(" callback="); b.append(callback.getClass().getName()); } else { b.append(" what="); b.append(what); } if (arg1 != 0) { b.append(" arg1="); b.append(arg1); } if (arg2 != 0) { b.append(" arg2="); b.append(arg2); } if (obj != null) { b.append(" obj="); b.append(obj); } b.append(" target="); b.append(target.getClass().getName()); } else { b.append(" barrier="); b.append(arg1); } b.append(" }"); return b.toString(); } public static final Parcelable.Creator<Message> CREATOR = new Parcelable.Creator<Message>() { public Message createFromParcel(Parcel source) { Message msg = Message.obtain(); msg.readFromParcel(source); return msg; } public Message[] newArray(int size) { return new Message[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { if (callback != null) { throw new RuntimeException( "Can't marshal callbacks across processes."); } dest.writeInt(what); dest.writeInt(arg1); dest.writeInt(arg2); if (obj != null) { try { Parcelable p = (Parcelable)obj; dest.writeInt(1); dest.writeParcelable(p, flags); } catch (ClassCastException e) { throw new RuntimeException( "Can't marshal non-Parcelable objects across processes."); } } else { dest.writeInt(0); } dest.writeLong(when); dest.writeBundle(data); Messenger.writeMessengerOrNullToParcel(replyTo, dest); dest.writeInt(sendingUid); } private void readFromParcel(Parcel source) { what = source.readInt(); arg1 = source.readInt(); arg2 = source.readInt(); if (source.readInt() != 0) { obj = source.readParcelable(getClass().getClassLoader()); } when = source.readLong(); data = source.readBundle(); replyTo = Messenger.readMessengerOrNullFromParcel(source); sendingUid = source.readInt(); } }
这是一个序列化的类,handler和intent传递消息都是需要序列化的数据来完成。接着回到Handler类里面,继续执行会执行到这个方法:
public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里MessageQueue就出现了,会把Message对象放入一个MessageQueue队列中,我们进入MessageQueue这个类里面:
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
这是一个同步的方法,会把Message对象放入MessageQueue里面。下面问题来了,Handler的handlerMessage什么时候会执行,我们看看HandlerMessage这个方法:
Handler类提供了一个Callback接口和handlerMessage方法,Handler类里还有dispatchMessage方法,调用了Callback接口和handlerMessage:
/** * 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); } }<span style="font-family:SimSun;font-size:14px;"></span>
但是dispatchMessage方法什么时候调用,我们就找到了Looper这个类了,这个类里有方法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(); } }线程建立消息循环机制,循环从MessageQueue获取Message对象,调用 msg.target.dispatchMessage(msg);进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理,那么Handler又是怎样与Looper建立联系的呢
那么问题又来了,Looper.loop()又啥时候会被调用,这个我们就找到了ActivityThread这个类(这个类在编辑器查看是被隐藏的,需要从浏览器中去查找Android源代码查看,这里我的查看地址:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/app/ActivityThread.java?av=fActivityThread向了解的可以自己去搜索一下,其实就是我们的UI线程,所以loop方法是在主线程中运行的),ActivityThread类里main函数里有这样的代码:
这里就会启动loop(),在for (;;) 执行。这里就通过源码分析了整个流程,Handler机制原理
相关文章推荐
- Missing Gradle Project Information
- Android Studio简记
- Android ViewPager监听其控件
- Android使用ImageView 制作透明圆弧实例代码
- Android学习笔记八:SQLite判断一张表是否存在
- Android之注解IOC(二)
- Android接口回调深入理解
- 关于5.0以下Android状态栏背景色变换
- Android杂谈(5):ViewPager中Fragment跳转时出现界面无任何展示
- android学习笔记-数据存储File SharedPreference Sqlite
- android studio 引用Lisbs的.so文件
- Android内核开发:如何统计系统的启动时间
- Android更新机制(自己服务器和GooglePlay更新)
- Android 应用:打包(签名文件)、代码混淆、应用加固、发布到应用商店
- android rootfs的挂载流程
- Android获得控件在屏幕中的绝对坐标
- Android获得控件在屏幕中的绝对坐标
- android 去除title标题
- Android热修复实践应用--AndFix
- Android attrs文件(自定义)属性详解