android进阶(十)-----Android消息机制

103 阅读2分钟

我正在参加「掘金·启航计划」

android消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。

一、android消息机制概述

Handler创建时采用当前线程的Lopper来构建内部的消息循环,如果当前线程没有Lopper,就会报错。

Handler创建完成后,内部的Looper以及MessageQueue就可以和Handler协同工作了,通过Handler的post方法将一个Runnable投递到Handler内部的Lopper中去处理,也可以通过Handler的send方法发送一个消息,这个消息会在Looper中去处理。当send方法被调用时,他会调用MessageQueue的enqueueMessage方法将这个消息放入MessageQueue中,Looper发现有新消息到来,就会处理这个消息,最终消息的Runnable或者Handler的handleMessage方法会被调用

二、Android的消息机制分析

1、MessageQueue的工作原理

消息队列主要包含两个操作:插入和读取。

读取操作本身会伴随着删除操作,插入和读取对应的方法分别为:enqueueMessage和next。

下面看一下源码:

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) { 
            msg.next = p; mMessages = msg; needWake = mBlocked; 
        } else { 
            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; 
        } 
        if (needWake) { 
            nativeWake(mPtr); 
        } 
    } 
    return true; 
}

从enqueueMessage的实现来看,他主要操作就是单链表的插入操作。

下面看next方法的逻辑:

Message next() { 
    final long ptr = mPtr; 
    if (ptr == 0) { 
        return null; 
    }   
    int pendingIdleHandlerCount = -1; 
    // -1 only during first iteration 
    int nextPollTimeoutMillis = 0; 
    for (;;) { 
        if (nextPollTimeoutMillis != 0) { 
            Binder.flushPendingCommands(); 
        }   
        nativePollOnce(ptr, nextPollTimeoutMillis);   
        synchronized (this) { 
            final long now = SystemClock.uptimeMillis(); 
            Message prevMsg = null; 
            Message msg = mMessages; 
            if (msg != null && msg.target == null) { 
                do { 
                    prevMsg = msg; msg = msg.next; 
                } while (msg != null && !msg.isAsynchronous()); 
            } 
            if (msg != null) { 
                if (now < msg.when) { 
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 
                } else { 
                    mBlocked = false; 
                    if (prevMsg != null) { 
                        prevMsg.next = msg.next; 
                    } else { 
                        mMessages = msg.next; 
                    } 
                    msg.next = null; 
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg); 
                    msg.markInUse(); return msg; 
                } 
            } else { 
                nextPollTimeoutMillis = -1; 
            } 
            if (mQuitting) { 
                dispose(); 
                return null; 
            } 
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { 
                pendingIdleHandlerCount = mIdleHandlers.size(); 
            } 
            if (pendingIdleHandlerCount <= 0) { 
                mBlocked = true; continue; 
            }   
            if (mPendingIdleHandlers == null) { 
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 
            } 
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 
        }   
        for (int i = 0; i < pendingIdleHandlerCount; i++) { 
            final IdleHandler idler = mPendingIdleHandlers[i]; 
            mPendingIdleHandlers[i] = null; // release the reference to the handler   
            boolean keep = false; 
            try { 
                keep = idler.queueIdle(); 
            } catch (Throwable t) { 
                Log.wtf(TAG, "IdleHandler threw exception", t); 
            }   
            if (!keep) { 
                synchronized (this) { 
                    mIdleHandlers.remove(idler); 
                } 
            } 
        } 
        pendingIdleHandlerCount = 0; nextPollTimeoutMillis = 0; 
    } 
}

可以发现next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里,有新消息时,next方法会返回这条消息并将其从单链表删除

2、Looper的工作原理

Looper会不停的从MessageQueue中查看是否有新消息,如果有就立刻处理,否则阻塞在哪里

首先看一下他的构造方法,在构造方法中会创建一个MessageQueue,然后将当前线程的对象保存起来,如下所示:

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

我们知道,Handler的工作需要Looper,没有Looper线程会报错,如何创建一个Looper哪,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.loop()来开启消息循环,如下所示:

new Thread("thread2"){ 
    @Override 
    public void run(){ 
        Looper.prepare(); 
        Handler handler = new Handler(); 
        Looper.loop(); 
    } 
}.start();

Looper除了prepare方法外,还提供了prepareMainLooper方法,这个方法主要是给主线程创建Looper使用,本质也是通过prepare实现的

Lopper也是可以退出的,Looper提供了quit和quitSafely来退出一个looper,二者的区别:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后再安全退出。looper退出后通过handler发送的消息会失败,handler的send方法会返回false。在子线程中如果手动创建了looper,那么在事情处理完成后应退出looper。

Looper最重要的方法是loop方法,只有调用loop后,消息循环系统才会真正起作用,源码如下:

public static void loop(){ 
    final Lopper me = myLooper(); 
    if(me == null){ 
        throw new RuntimeException("No Looper;Looper.prepare() wasn ' t called on this thread") 
    } 
    final MessageQueue queue = me.mQueue; 
    Binder.clearCallingIdentity(); 
    final long ident = Binder.clearCallingIdentity(); 
    for(;;){ 
        Message msg = queue.next(); 
        if(msg == null){ 
            return; 
        } 
        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); 
        } 
        final long newIdent = Binder.clearCallingIdentity(); 
        if(iden != newIdent){ 
            Log.wtf(TAG,"Thread identity changed form 0x" +Long.toHexString(ident)+"to 0x" +Long.toHexString(newIdent)+"while dispatching to" +msg.target.getClass().getName()+"" +msg.callback+"what="+msg.what); 
        } 
        msg.recycleUnchecked(); 
    } 
}

loop方法是一个死循环,唯一跳出循环的方式MessageQueue的next方法返回null。当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法通知消息队列退出,当消息队列被标记为退出状态时,他的next方法就会返回null

3、Handler的工作原理

Handler的工作主要包含消息的发送和接受过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现,post的一系列方法最终是通过send的一系列方法来实现的。

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); 
} 
public boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){ 
    msg.target = this; 
    if(mAsynchronous){ 
        msg.setAsynchronous(true); 
    } 
    return queue.enqueueMessage(msg,uptimeMillis); 
}

Handler发送消息的过程仅仅是向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交由Handler处理,即Handler的dispatchMessage方法会被调用,这个Handler就进入了处理消息的阶段。

dispatchMessage代码如下:

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

三、主线程的消息循环

Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环。

public static void main(String[] args){ 
    Process.setArgV0("<pre-initialized>"); 
    Looper.prepareMainLooper(); 
    ActivityThread thread = new ActivityThread(); 
    thread.attach(false); 
    if(sMainThreadHandler == null){ 
        sMainThreadHeadler = thread.getHandler(); 
    } 
    AsyncTask.init(); 
    if(false){ 
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,"ActivityThread")); 
    } 
    Looper.loop(); 
    throw new RuntimeException("Main thread loop unexpectedly exited"); 
}

主线程的消息循环开始以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程,代码如下:

private class H extends Handler{ 
    public static final int LAUNCH_ACTIVITY =100; 
    public static final int PAUSE_ACTIVITY =101; 
    public static final int PAUSE_ACTIVITY_FINISHING =102; 
    public static final int STOP_ACTIVITY_SHOW =103; 
    public static final int STOP_ACTIVITY_HIDE =104; 
    public static final int SHOW_WINDOW =105; 
    public static final int HIDE_WINDOW =106; 
    public static final int RESUME_ACTIVITY =107; 
    public static final int SEND_RESULT =108; 
    public static final int DESTROY_ACTIVITY =109; 
    public static final int BIND_APPLICATION =110; 
    public static final int EXIT_APPLICATION =111; 
    public static final int NEW_INTENT =112; 
    public static final int RECEIVER =113; 
    public static final int CREATE_SERVICE =114; 
    public static final int SERVICE_ARGS =115; 
    public static final int STOP_SERVICE =116; ...... 
}

ActivityThread通过ApplicationThread和AMS进行进程间通信。AMS以进程通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H接受到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程去执行,这个过程就是主线程的消息循环模型。