当前位置: 代码迷 >> 综合 >> Handler的原理及源码分析
  详细解决方案

Handler的原理及源码分析

热度:12   发布时间:2024-02-02 10:00:23.0

Handler在安卓中起到了很重要的作用,也是面试中经常被提问到的点,下面我们从源码来分析下Handler

首先,Handler在安卓中有什么作用?

1、因为安卓不能在主线程做耗时的操作,耗时操作需要在子线程中操作,但是子线程不能更新UI,因此需要Handler在子线程发消息给主线程来更新UI

其次,Handler的原理机制

      Handler有4个对象handler、Message、MessageQueue、Looper;

       1、MessageQueue:消息队列,相当于传送带,负责Message队列的传送与管理

       2、Looper是流水线的发动机,不断的把消息从消息队列中取出来,交给Handler处理

       3、Message相当于传送带上的产品

       4、handler传送带最终将产品交给handler处理

handler调用sendMessager的时候会将Messager放入消息队列中,Looper在应用启动的时候,就已经启动了,在不停的循环,从消息队列中获取消息,如果有消息,将消息交给handler,handler调用handleMessage进行消息的处理

从源码分析Looper、MessageQueue

    1、 Looper何时创建?Looper中两个重要的方法prepare()和loop()的作用?

        android主线程在创建的时候会主动创建一个Looper

        ActivityThread是安卓的主线程,在ActivityThread的main函数中创建了Looper

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 libcoreEventLogger.setReporter(new EventLoggingReporter());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");//创建LooerLooper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//创建loop成功后,就开启消息队列的无线循环Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

调用Looper.prepareMainLooper方法,创建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();}}

 在prepare中创建Looper,并将Looper和当前线程绑定,在创建之前,会判断该线程中是否存在Looper,如果存在,会抛出异常,提示该线程已经创建Looper了

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

new Looper创建Looper的时候:

private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}

会新建一个MessageQueue消息队列,并获取当前线程的引用

Looper中另一个重要方法loop()是干什么的呢?

  该方法主要是不断的从消息队列中拿消息,其源码如下:

 /*** Run the message queue in this thread. Be sure to call* {@link #quit()} to end the loop.*/public static void loop() {//获取Looper对象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 blockif (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 loggerfinal 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 {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();}}

loop获取Looper对象,然后looper对象中获取MessageQueue对象,然后开启一个无限循环,这个循环就是不停的从MessageQueue中取消息,并将取出消息交给handler的dispatchMessage()来处理,只有当queue.next()取得Message为null的时候才跳出循环

public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

最终将消息回调到handleMessage处理

 

Looper的其他方法

//获取当前线程的Looper
Looper looper = Looper.myLooper();
//获取主线的Looper
Looper mainLooper = Looper.getMainLooper();
//清除全部消息
looper.quit();
//清除延迟消息
looper.quitSafely();

handler调用不管是调用sendMessage、sendEmptyMessage、sendEmptyMessageDelayed都是调用sendMessageAtTime方法,

 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);}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}
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 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.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true;}

获取消息队列对象,并将消息插入到消息队列中

 

 

总结:在activity启动的时候,创建了Looper对象,创建Looper对象的时候,创建了MesageQueue队列,并开启MessageQueue的无限循环。当handler调用sendMessage发送消息的时候,会将Message插入到消息队列中,消息队列不停循环,当有消息的时候,Loope人取出消息,交给handler,handler回调handleMessage处理消息

 

 

  相关解决方案