Android消息处理机制Handler

时间:2021-09-01 17:49:45

Handler机制的作用:

可以实现线程见得通讯,将数据封装到消息中,并将消息发送给UI线程,并取出消息中的数据刷新UI。

涉及到Handler机制的4个重要的类:

                Handler:发送消息到MessageQueue,Looper循环拿出消息,交给Handler的handlermessage处理
Message:消息;包含消息描述和数据
Looper:循环消息,当消息队列有消息的时候,Looper不断循环的处理消息,当消息队列没有消息了,Looper就阻塞在原地
MessageQueue:消息队列,用于储存消息

Handler类:

public Handler(Looper looper) {
				this(looper, null, false);
			}
			
			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();
				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;
			}

从sThreadLocal取出looper,如果sThreadLocal中有就返回looper没有就返回空

public static @Nullable Looper myLooper() {
				return sThreadLocal.get();
			}
是从哪里给sThreadLocal设置looper的?Looper.prepare()
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));
			}
从上面可以看出,首先判断sThreadLocal是否存在Looper,如果没有就创建一个新的Looper设置进去。所以我们要先调用Looper.prepare(),才能创建Handler对象(否则会抛出异常"Can't create handler inside thread that has not called Looper.prepare()"),每个线程也只会创建一个Looper对象。


为什么在主线程中不需要我们手动创建Looper?查看ActivityThread中的main():
public static void main(String[] args) {
						Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
						SamplingProfilerIntegration.start();

						// CloseGuard defaults to true and can be quite spammy.  We
						// disable it here, but selectively enable it later (via
						// StrictMode) on debug builds, but using DropBox, not logs.
						CloseGuard.setEnabled(false);

						Environment.initForCurrentUser();

						// Set the reporter for event logging in libcore
						EventLogger.setReporter(new EventLoggingReporter());

						// Make sure TrustedCertificateStore looks in the right place for CA certificates
						final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
						TrustedCertificateStore.setDefaultUserDirectory(configDir);

						Process.setArgV0("<pre-initialized>");

						// 这里调用了prepareMainLooper()
						Looper.prepareMainLooper();

						ActivityThread thread = new ActivityThread();
						thread.attach(false);

						if (sMainThreadHandler == null) {
							sMainThreadHandler = thread.getHandler();
						}

						if (false) {
							Looper.myLooper().setMessageLogging(new
									LogPrinter(Log.DEBUG, "ActivityThread"));
						}

						// End of event ActivityThreadMain.
						Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
						Looper.loop();

						throw new RuntimeException("Main thread loop unexpectedly exited");
					}
prepareMainLooper():
public static void prepareMainLooper() {
						// 在这里调用prepare方法创建Looper,并设置到sThreadLocal中
						prepare(false);
						
						synchronized (Looper.class) {
							if (sMainLooper != null) {
								throw new IllegalStateException("The main Looper has already been prepared.");
							}
							// 从sThreadLocal取出上面创建的Looper对象赋值给sMainLooper
							sMainLooper = myLooper();
						}
					}
发送消息:handler.sendMessage(msg);

public final boolean sendMessage(Message msg)
				{
					return sendMessageDelayed(msg, 0);
				}
			
				public final boolean sendMessageDelayed(Message msg, long delayMillis)
				{
					if (delayMillis < 0) {
						delayMillis = 0;
					}
					return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
				}
/**
				 * msg:发送的消息
				 * uptimeMillis:发送消息的时间,如果不是调用的sendMessageDelayed(),时间都会为0
				 */
				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);
				}
sendMessageAtFrontOfQueue():将消息添加到消息队列的头部位置
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);
				}
MessageQueue的enqueueMessage方法:
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(TAG, e.getMessage(), e);
							msg.recycle();
							return false;
						}

						msg.markInUse();
						msg.when = when;
						// 只是使用一个message对象来标识当前的处理的消息
						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;
				}
所有的消息入队列其实就是将所有的消息按时间来进行排序,这个时间就是我们传入的uptimeMillis。具体操作就是根据时间顺序调用msg.next,从而为每个消息指定它下一个消息是什么。如果是通过sendMessageAtFrontOfQueue()来发送消息,它会调用enqueueMessage()来让消息入队列,时间为0,会把mMessage赋值为新入队的这条消息,然后将这条消息的next指定为刚才的mMessages,这样就完成了消息队列的头部添加。

从队列里取出消息: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 (;;) {
						
							// 通过一个死循环不断地调用MessageQueue的next()方法来取出消息
							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
							final Printer logging = me.mLogging;
							if (logging != null) {
								logging.println(">>>>> Dispatching to " + msg.target + " " +
										msg.callback + ": " + msg.what);
							}

							final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

							final long traceTag = me.mTraceTag;
							if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
								Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
							}
							final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
							final long end;
							try {
							
								// 每当有一个消息出队列,就会调用Handler的dispatchMessage()方法
								msg.target.dispatchMessage(msg);
								end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
							} finally {
								if (traceTag != 0) {
									Trace.traceEnd(traceTag);
								}
							}
							if (slowDispatchThresholdMs > 0) {
								final long time = end - start;
								if (time > slowDispatchThresholdMs) {
									Slog.w(TAG, "Dispatch took " + time + "ms on "
											+ Thread.currentThread().getName() + ", h=" +
											msg.target + " cb=" + msg.callback + " msg=" + msg.what);
								}
							}

							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();
						}
					}

Handler的dispatchMessage()方法:转发处理消息

public void dispatchMessage(Message msg) {
						if (msg.callback != null) {
							handleCallback(msg);
						} else {
						
						// 如果mCallback,就调用mCallback.handleMessage(msg),否则直接调用Handler的handleMessage(msg),
						// 我们就可以在handleMessage()中获取到之前发送的消息了
							if (mCallback != null) {
								if (mCallback.handleMessage(msg)) {
									return;
								}
							}
							handleMessage(msg);
						}
					}

总结:

Handler机制的流程:
1、将子线程中获取到的数据封装在Message对象中
2、通过handler.sendMessage()或者handler.post()将消息发送到消息队列中,最终都是走的sendMessageAtTime(),在sendMessageAtTime中调用了MessageQueue的enqueueMessage(),完成消息插入到队列的操作
3、每次我们创建Hanlder实例时,都会初始化Looper对象,是调用Looper.prepare()创建Looper对象,将Looper对象通过
ThreadLocal存入到线程中
4、Looper调用Looper.loop() --> MessageQueue.next()从消息队列中不断取出消息
5、取出来的消息通过handler.dispatchMessage()转发处理

还有以下几种方式可以在子线程中操作UI:

    1、handler.post():

public final boolean post(Runnable r)
			{
			// 还是调用了sendMessageDelayed去发送消息
			   return  sendMessageDelayed(getPostMessage(r), 0);
			}
			
			/**
			 * 将Runnable对象转化成Message对象
			 */
			private static Message getPostMessage(Runnable r) {
				Message m = Message.obtain();
				m.callback = r;
				return m;
			}

在handler的dispatchMessage中有个判断,msg.callback如果不为null就会进入以下方法:

private static void handleCallback(Message message) {
				// 直接就调用了Runnable对象的run()
					message.callback.run();
				}

    2、view.post(): 就是调用的Handler的post()

public boolean post(Runnable action) {
				final AttachInfo attachInfo = mAttachInfo;
				if (attachInfo != null) {
				
					return attachInfo.mHandler.post(action);
				}

				// Postpone the runnable until we know on which thread it needs to run.
				// Assume that the runnable will be successfully placed after attach.
				getRunQueue().post(action);
				return true;
			}

    3、Activity的runOnUiThread():

 @Override
				public final void runOnUiThread(Runnable action) {
				
					// 如果不是主线程就调用Handler的post(),否则就直接调用Runnable的run()
					if (Thread.currentThread() != mUiThread) {
						mHandler.post(action);
					} else {
						action.run();
					}
				}