Android的消息机制

作者: Arestory | 来源:发表于2018-02-28 17:09 被阅读27次

    总的来说,Android应用程序是通过消息来驱动的,Android也可以说是一个以消息驱动的系统,UI、生命周期等各种事件和消息处理机制息息相关,所以消息处理机制在整个Android知识体系中是非常重要的,但是网上关于Android消息机制的文章,大多都长篇大论,如果没有足够的耐心,很难阅读并理解下去,所以,我觉得在汲取别人文章知识的同时,也需要自己去花功夫去总结出自己的结论,才能记忆深刻。

    组成成员

    • Looper 消息轮询器
    • MessageQueue 消息队列
    • Message 消息载体
    • Handler 发送与处理消息者

    原理简述

    App启动时,在ActivityThread的main方法里,调用了Looper.prepareMainLooper(),创建一个全局主线程的Looper(通过ThreadLocal将Looper与主线程绑定,并确保一个线程只有一个Looper),这个Looper在实例化的同时,会实例化一个消息队列MessageQueue,在Looper.prepareMainLooper()完毕后,main方法继续调用Looper.loop(),主线程的Looper进入一个无限的for循坏,在这个for循环里,looper会不断从自己的消息队列MessageQueue中查询消息,当队列中没有消息时,CPU会腾出资源给其他线程,当队列中有消息Message时,由于Message会持有一个handler对象,那么此时会迫使handler调用dispatchMessage方法,而在dispatchMessage方法里面,则会继续调用我们最熟悉的handleMessage方法了。
    由于handler自身持有主线程的Looper(该handler是在主线程实例化的前提下),当我们利用handler发送消息时,会通过Looper中的消息队列MessageQueue插入消息,那么在loop方法里的无限for循坏就会取出这条消息,handler执行这条消息,因此其他线程可以通过这个handler,与主线程进行消息传递,从而形成这个完整的消息机制。

    值得注意的是,在其他线程创建Handler时,必须首先调用Looper.prepare(),在该线程才会持有对应的Looper,否则会抛出异常

    例子

    我们通过一个例子来概括:
    某公司有一个24小时运行的请假系统(即APP的主线程),系统会有一个请假列表(即MessageQueue),请假者(Handler)发送休假申请到系统时,会自动插一条请假记录(Message)到列表中,系统的工作就是不断查询列表是否有休假申请,如果有,就一条条进行审核,并将审核结果发送到请假者的手机上,请假者根据审核结果行动;如果列表中没有记录,系统就将进入休眠状态(即线程堵塞),但是当系统收到一条休假申请时,系统会自动恢复工作状态,继续进行审核。

    源码分析

    首先,从App的入口,即ActivityThread

    public final class ActivityThread {
        ...
    
            ActivityThread() {
                mResourcesManager = ResourcesManager.getInstance();
            }
        ...
        public static void main(String[] args) {
        ...
    
         //创建一个主线程的Looper
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        ...
    
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //进入一个无限的消息读取操作
        Looper.loop();
    
       ...
       
       }
     ...
    }
    

    由以上源码可见ActivityThread并不是一个线程类,只是一个普通类,在其主方法中调用了

     Looper.prepareMainLooper() 
     Looper.loop() 
    

    来大致看看Looper的源码

    public final class Looper {
    ...
        //ThreadLocal,线程本地存储区,这里用于存放线程对应的Looper
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        //主线程的Looper
        private static Looper sMainLooper;  // guarded by Looper.class
        //Looper持有的消息队列
        final MessageQueue mQueue;
        //Looper的所属线程
        final Thread mThread;
        //实际上调用了prepare方法,并且利用synchronized锁,确保主线程只有一个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();
        }
        }
    
        public static void prepare() {
           prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
            //如果线程储存区已经有Looper,抛出异常
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
         }
         //保存一个新的Looper
         sThreadLocal.set(new Looper(quitAllowed));
        }
    
        //私有构造方法
        private Looper(boolean quitAllowed) {
            //实例化一个队列
              mQueue = new MessageQueue(quitAllowed);
          //赋值当前线程给mThread变量
         mThread = Thread.currentThread();
        }
    
        //获取线程的Looper
        public static @Nullable Looper myLooper() {
         return sThreadLocal.get();
        }
    
        //方便获取主线程的Looper
        public static Looper getMainLooper() {
           synchronized (Looper.class) {
              return sMainLooper;
         }
        }
    }
    
    //进入无限循环,不断读取消息,当队列中有消息时,通过消息中的handler对象的dispatchMessage方法分发消息
    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 block
            //没有消息时,自身堵塞
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
    
            ...
            try {
                    //Message对象持有一个target即Handler对象,利用它的dispatchMessage方法进行消息分发
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           ...
                //将Message回收到消息池,下次要用的时候不需要重新创建,obtain()就可以了。
               msg.recycleUnchecked();
        }
    }
    
    

    那么,APP启动时,并创建了一个属于主线程的Looper,而这个Looper也拥有自己的消息队列,主线程已经开始在无限循环中不断查询消息了,那么系统是怎样发送消息到主线程中去,而主线程又如何处理这些消息?

    注:Binder线程:具体是指ApplicationThread,在App进程中接受系统进程传递过来的信息的线程(这个线程的创建时间先于主线程)。

    接下来,我们来探讨一下Activity的启动流程:当APP准备启动一个Activity的时候,系统服务进程下的ActivityManagerService(AMS)线程会通过Binder线程发送IPC调用给APP进程,App进程接到到调用后,通过App进程下的Binder线程最终调用ActivityThread类下面的scheduleLaunchActivity方法来准备启动Activity,看下scheduleLaunchActivity方法:

    
    //这个方法不是在主线程调用,是Binder线程下调用的
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
     
      updateProcessState(procState, false);
      ActivityClientRecord r = new ActivityClientRecord();
      r.token = token;
      r.ident = ident;
      ...
      
       updatePendingConfiguration(curConfig);
       
       //将信息内容封装成ActivityClientRecord,发送启动activity的指令
       sendMessage(H.LAUNCH_ACTIVITY, r);
      
      
      }
      
      private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
        }
    
    
        private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) 
        {
         if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }
     
    

    由上面的代码可以知道,最后通过变量mH来发送消息,那么重新查阅ActivityThread的源码,可以得知它就是一个继承Handler的H类,它帮我们处理许多activity生命周期的事情

    public final class ActivityThread {
    
        ...
    
        final H mH = new H();
    
        ...
    
        private class H extends Handler {
        ...
    
            public void handleMessage(Message msg) {
                switch (msg.what) {
             //进行一系列指令操作
                }
            }
    ...
        }
    }
    

    到此为止,我们对启动流程有了较为清晰的了解,那么Handler又是如何将消息发送到线程的消息队列中去呢?再来简单看看Handler的源码

    public class Handler {
    
    
    ...
    //可见,内部有Looper和MessageQueue成员
    final Looper mLooper;
    final MessageQueue mQueue;
    ...
    
    //我们常用的无参构造
    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());
            }
        }
         //得到当前线程的Looper
        mLooper = Looper.myLooper();
        
        /* 
         * 如果在一个新线程中,实例化Handler前,必须先调用Looper.prepare()
         */
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //得到Looper的消息队列
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    
    /**
     * 
     *  所有发送消息的方法,最终都会调用到此方法
     */
    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) {        
        //将消息中的target赋值为当前handler
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //将消息插入队列中
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    
    
    }
    
    

    由Handler的源码可知,handler在发送消息时,会将消息插入其持有的Looper所对应的消息队列中,即以上代码的queue.enqueueMessage

    
    public final class MessageQueue {
    
        ...
        private final boolean mQuitAllowed;
        ...
    
    
        //将消息按时间插入队列中
        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();
            //when 表示这个消息执行的时间,队列是按照消息执行时间排序的
            //如果handler 调用的是postDelay 那么when=SystemClock.uptimeMillis()+delayMillis
            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.
                // p==null 表示当前消息队列没有消息
                msg.next = p;
                mMessages = msg;
                //需要唤醒主线程,如果队列没有元素,主线程会堵塞在管道的读端,这时
                //候队列突然有消息了,就会往管道写入字符,唤醒主线程
                needWake = mBlocked;
            } else { 
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //将消息放到队列的确切位置,按照msg的when 排序的
                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;
    }
    
    }
    
    

    回顾一下Looper的源码,在loop方法中无限的for循环中看到,当队列中有消息时,消息对象持有一个target即Handler对象,利用它的dispatchMessage方法进行消息分发

      msg.target.dispatchMessage(msg);
    

    再补充一下Handler的分发消息的部分代码

    public class Handler {
    
    ...
    //这里方法内容为空,因为后续由开发人员操作
    public void handleMessage(Message msg) {
    }
    
    /**
     * 可以看到,最后会调用handleMessage(当回调接口为空时)
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    
    ...
    
    }
    
    
    

    相关文章

      网友评论

        本文标题:Android的消息机制

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