Android Handler消息处理机制(菜鸟篇)

作者: 淋雨仔 | 来源:发表于2016-09-13 22:59 被阅读517次

    网上有很多关于Handler,Looper,Message的分析。
    但是很多都是大概的讲了一个思路,并且只是挑了几个重点做了比较详细的叙述,只要不是自己本来就了解的很清楚,看完以后一般都有点云里雾里。
    比如说提到MessageQueue.next()这个方法,由native方法阻塞获取Message和监听event触发什么的,没看过源码的连MessageQueue.next()在Looper里面调用都不知道,要怎么跟上你的思路 !!!


    这篇文章仅仅写一个Message的send到handle过程,不深入到native,不考虑线程同步等等问题。
    我觉得首先了解是怎么工作的,将整个流程熟悉了之后,再考虑底层的实现以及一些线程同步,数据储存方式和异常发生的情况。


    其实大概的原理就是,Handler发送Message到MessageQueue,Looper从MessageQueue中取出Message执行。


    另外这些类的关系,一个线程最多只有一个Looper,一个Looper持有一个MessageQueue,一个Looper可以对应多个Handler。可以下面列出这些类和在这片文章里需要用到的成员。

    Class Fields
    Message 1.target(Handler)
    是一个Handler
    标记Message属于哪个Handler
    2.when(long)
    什么时候发送这个messag
    3.next(Message)
    可以作为一个List
    4.另外就是一些数据了
    MessageQueue Message
    用Message.next组成List
    Looper 1.ThreadLocal
    可以说是用来保存
    某个线程的Looper
    2.MessageQueue
    Looper持有的MessageQueue
    Handler MessageQueue
    通过其所属的Looper
    得到MessageQueue

    好了,下面是重头戏(有点啰嗦,见谅),我们知道UI线程自动帮你创建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(false),忽略那个boolean值

    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用的ThreadLocal

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    

    然后进去看get方法

    public T get() {    
        // Optimized for the fast path.    
        Thread currentThread = Thread.currentThread();    
        Values values = values(currentThread);    
        if (values != null) {        
            Object[] table = values.table;        
            int index = hash & values.mask;        
            if (this.reference == table[index]) {            
                return (T) table[index + 1];        
            }    
        } else {        
            values = initializeValues(currentThread);    
        }    
        return (T) values.getAfterMiss(this);
    }
    
    Values values(Thread current) {    
        return current.localValues;
    }
    

    可以看到Values是通过Thread拿到的,进到Thread.class可以看到类型为ThreadLocal.Values的值

    /** * Normal thread local values. */
    ThreadLocal.Values localValues;
    

    我们暂时先不深入下去了解是怎么存储的,只要知道Looper是通过ThreadLocal.Values来取的,当然也是通过这个来存的。
    我们回到prepare()方法,程序刚启动,所以可以确定sThreadLocal.get() = null,所以会执行sThreadLocal.set(new Looper(quitAllowed)),也就是给UI的线程新建一个Looper。
    然后我们继续看Looper的构造器

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

    我们可以看到Looper在new的时候会持有一个MessageQueue,现在Looper,MessageQueue已经准备就绪了。
    之后,只要调用Looper.loop()就能让Looper循环去取Message,我们来看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();    
        }
    }
    

    我们先来看开头

    final Looper me = myLooper();
    

    中的myLooper()

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

    我们可以看到当前线程的Looper就是通过sThreadLocal.get(),也就是Thread.currentThread().localValues这个值来拿的,现在我们已经拿到的当前线程的Looper。
    然后我们再看这句

    final MessageQueue queue = me.mQueue;
    

    我们之前看到Looper的构造器里new了一个MessageQueue,所以我们现在得到了当前线程的Looper所持有的MessageQueue,之后在for里面不断从MessageQueue里面取Message

    Message msg = queue.next(); 
    

    其中queue.next()里面有很多native方法,这里先不深入,另外queue.next()这个方法会在没有message的时候阻塞,拿到Message之后,看下面这句

    msg.target.dispatchMessage(msg);
    

    之前说到Message里面有一个target是Handler类型,也就是发送这个Message的Handler。
    然后进Handler看dispatchMessage方法

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

    我们可以看到handleMessage()这个方法,这也就是Looper从MessageQueue里拿Message给它自己的Handler处理的过程。
    现在整个消息循环系统已经建成了,我们只需要同Handler发Message即可。
    我们先新建一个Handler

    public Handler() {    
        this(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;
    }
    

    我们看这两句

    mLooper = Looper.myLooper();
    mQueue = mLooper.mQueue;
    

    Handler持有了当前线程的Looper的MessageQueue,现在我们发消息handler.sendMessage();

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

    我们可以看到msg.target = this,给message的target设置为当前的handler,这样就可以调用指定handler的dispatchMessage方法了,就像上面写到的msg.target.dispatchMessage(msg)。
    然后用在Handler进行new的时候持有的MessageQueue执行enqueueMessage方法,我们看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 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按照when(执行的时间)插入到一个Message链表,和指针的写法是一样的(这部分看不懂的自觉面壁思过)
    最后扯一丢丢native的方法,就是最后nativeWake(mPtr)这个方法,简单点说就是通知有新的Message,然后Looper.loop()里面Message msg = queue.next();这句本来阻塞的方法就能拿到最新的Message。


    这篇文章主要就是讲handler.sendMessage()之后到handler.handleMessage()的过程,关于native,线程同步,以及其他情况的考虑,之后会在这篇的基础上另外写一篇更深入的。
    总觉得写来写去还是写的不够好,不晓得你们能不能看懂= =
    如果有写的不正确的地方,就赶快告诉我啊哈哈哈

    相关文章

      网友评论

        本文标题:Android Handler消息处理机制(菜鸟篇)

        本文链接:https://www.haomeiwen.com/subject/ggwmettx.html