Android源码学习笔记:Handler机制

来源:互联网 发布:如何网络人肉 编辑:程序博客网 时间:2024/06/05 12:50

转载请注明出处 tianyl_Melodie 的博客,http://blog.csdn.net/tianyl_melodie/article/details/53397283

1、说明


相信很多人面试的时候都被问到过Handler的机制,作为Android中的消息处理机制,Handler用到的地方非常多,所以我的Android源码学习笔记,也决定从Handler开始。

2、Looper和MessageQueue的构建


Handler,就不得不从Looper和MessageQueue说起了。在应用创建的时候,会创建一个ActivityThread对象,在ActivityThread.java的main方法中,则会完成Looper和MessageQueue对象的创建。
public static void main(String[] args) {        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());        Security.addProvider(new AndroidKeyStoreProvider());        Process.setArgV0("<pre-initialized>");//构建主线程中的MessageQueue和Looper对象        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        AsyncTask.init();        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

在main方法中,会调用Looper.prepareMainLooper()方法,此方法则会完成Looper和MessageQueue的初始化。

我们接下来往下看prepareMainLooper方法:
public static void prepareMainLooper() {    //构建MessageQueue和Looper对象        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }//获取sThreadLocal中set的Looper对象,作为MainLooper            sMainLooper = myLooper();        }    }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));    }

在prepareMainLooper的方法中,首先会调用prepare(false)这个方法,这个方法做的就是创建Looper对象。再看看Looper对象的构造函数:
private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mRun = true;        mThread = Thread.currentThread();    }

在构造函数中,会创建一个MessageQueue对象,。再看MessageQueue的构造函数:
MessageQueue(boolean quitAllowed) {        mQuitAllowed = quitAllowed;        mPtr = nativeInit();    }

可以发现此处调用了一个nativeInit的方法,可以看出MessageQueue的初始化是通过调用jni进行完成的。

至此,Looper和MessageQueue就已经创建完成了。由如上步骤可知:
ActivityThread.main() --> Lopper. prepareMainLooper() --> Lopper. prepare(false) --> new Looper() --> new MessageQueue();
这些就是Looper和MessageQueue的创建过程。
那么Handler又是如何创建的呢?他们又是如何进行绑定的呢?

3、Handler的创建


因为Handler是我们使用的时候才会创建出来,所以在创建ActivityThread的时候,系统并不会直接创建出Handler,那么在我们使用的时候,通过new Handler()创建Handler的时候,又发生了哪些事情呢?
首先,先看Handler无参的构造函数;
public Handler() {        this(null, false);    }
调用了两个参数的构造函数,传入了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());            }        }        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;    }

public static Looper myLooper() {        return sThreadLocal.get();    }

这里,就是系统在我们创建Handler的时候,为我们所做的事情了。
前几行是输出的一些日志信息,然后通过Looper的myLooper()方法,拿到mLooper对象。而通过Looper. myLooper()拿到的对象,就是我们之前在构建Loopeer的时候,通过sThreadLocal.set(new Looper(quitAllowed))方法设置进去的,到此,系统就保证了每一个Handler都会持有一个唯一的Looper对象。
在拿到了需要的Looper对象之后,将Looper.mQueue对象保存了起来,这个对象就是之前在Looper的构造方法中,创建的MessageQueue对象。
至此,Handler的创建也完成了,在我们创建Handler的时候,系统将Looper和MessageQueue都保存到了Handler中,这两个对象在ActivityThread都是唯一的,这样就保证了不论有多少个Handler,都能保证所有Handler发送的消息都能在一个地方进行处理。

4、Handler消息的发送


知道的Handler、Looper和MessageQueue这三者是如何构建和联系的,那么消息又是如何发送的呢?因为最常用的发送消息的方法是sendMessage(Message msg),当然,如果使用其他的方法,最后还是会调用到相同的方法的,所有首先看这个方法:
public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }
在sendMessage的方法中,调用了 sendMessageDelayed(msg, 0)这个方法,接下来往下看:
public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }
如果delayMillis小于0,那么将其制成0,并且调用sendMessageAtTime(Message msg, long uptimeMillis)这个方法:
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,在sendMessageAtTime这个方法中,开始发送消息。
首先:系统会拿到MessageQueue这个对象的实例,之前在构建Handler的时候,这个对象已经作为成员变量保存起来了。然后将取出MessageQueue的传入方法enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis):
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,然后调用MessageQueue的enqueueMessage:
boolean enqueueMessage(Message msg, long when) {        if (msg.isInUse()) {            throw new AndroidRuntimeException(msg + " This message is already in use.");        }        if (msg.target == null) {            throw new AndroidRuntimeException("Message must have a target.");        }        synchronized (this) {            if (mQuitting) {                RuntimeException e = new RuntimeException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage(), e);                return false;            }            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;    }
这个方法有点长,我们慢慢看:
首先,msg.target == null这个判断我们知道,就在之前的Handler调用enqueueMessage的时候,已经把自己保存到了msg.target中,所以此处不应该为空,否则就抛出异常,不能继续往下执行了,那么msg.isInUse()又是做什么呢?通过方法名我们就可以看出,消息是否在使用。 其实在调用msg.next()方法的时候,系统就会将这个值设为true。
在接下来的synchronized的方法中,首先会判断是否已经退出,如果已经退出,那么就不做任何操作,直接返回;
然后,将传入的when保存到msg.when中,之前在Handler的sendMessageDelayed中,我们已经知道,发送消息最后是用的sendMessageAtTime方法,而这个时候,如果有delayMillis,那么会将系统的当前时间和delayMillis的和作为参数传进来。所以这里我们可以知道这个when,其实就是希望msg真正生效的时间。

接下来的if-else判断,就是将消息添加到消息队列中了。
在这里,首先会将之前排序正确的消息队列保存到一个临时变量p中。为什么我要说排序正确呢?
因为虽然我们发送消息的这个动作是有序的,但是这并不能保证我们发送消息之后,执行的顺序和我们发送消息的顺序一样。
比如:我们先发送了一个10点执行的消息,又发送了一个8点执行的消息,所以虽然8点执行的消息是后发的,但是它需要在前面执行,所以在系统把消息添加到消息队列的时候,会依据消息所需要执行的时间进行排序。而这里的这个if-else就行对这些消息按照执行时间排序并添加到消息队列的逻辑。

在if中,如果when < p.when,也就是说,如果现在发送的消息的执行时间在已有的消息队列执行时间的前面,那么就将传入的msg.next指向已有的消息队列。
如果执行的是else逻辑,那么说明已有消息队列的消息执行时间小于传入消息的执行时间。那么就需要进行一系列的判断了。else中的for就是进行此操作的。
在for循环中,会不断的取出消息队列中的消息,拿该消息的生效时间和传入消息的生效时间,如果还是小于传入消息的生效时间,那么保存为prev ,继续拿下一条消息,继续比较,直到拿到比传入消息生效时间大的,则跳出循环。然后将传入消息的msg.next指向刚才找到的这条消息,将prev的下一条消息指向传入的msg。
至此,一个链式的消息队列就算完成了。如下图:


到此,消息的发送就完成了。那么发送的消息又是如果被执行的呢?

5、消息的轮询


在ActivityThread的main方法中,最后会执行这样一行代码: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.recycle();        }    }

在loop方法中,首先会通过myLooper拿到looper对象,之前我们已经看到它是在prepare方法中set的,然后拿到这个looper对应的MessageQueue对象。然后通过msg.target.dispatchMessage(msg)这个方法调用到HandlerdispatchMessage方法。
public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

dispatchMessage方法中,首先,会判断msg自己是否已经设置了callback方法,如果已经有callbakc方法,那么就用自己的callback方法,否则再看Handler是否有callback方法,此callback就是我们在构造Handler对象时传入的callback,最后,如果都没有,则会走handleMessage方法。到这里,Handler在发送消息时所有会做的事情基本学习完毕了。
0 0
原创粉丝点击