Android中消息机制与Handler源码解析

Android中消息机制与Handler源码解析

Android中消息机制构成整个Android系统的应用运行基础,我们都知道在每个应用主UI线程都存在一个消息循环系统也就是我们常说的MainLoop. Android应用中每一个交互动作都是转换消息Message来通知,以便触发执行相应的动作。

一、ActivityThread中的main函数作为应用的主入口函数

   public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();//初始化主Looper和MessageQueue
        ...

        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...

        Looper.loop();//通过Looper中loop不断从MessageQueue读取消息处理

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

二、初始化Main Looper(主循环系统)和MessageQueue(消息队列)

1、进入Looper.prepareMainLooper()方法

    //Looper.java
    public static void prepareMainLooper() {
        prepare(false);//先调用Looper中的prepare方法来创建一个Looper对象,并把创建的Looper实例存储在ThreadLocal中,ThreadLocal表示存储只与指定线程绑定的数据,也就是存储了主线程的Looper实例。
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();//调用myLooper方法获取存储在sThreadLocal中的Looper实例,并初始化sMainLooper.
        }
    }

2、接着Looper.prepareMainLooper()跳到prepare()方法

   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));//将创建好的Looper实例,通过ThreadLocal的set存储在Looper的sThreadLocal中。
    }

  //Looper构造器  
  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//创建了一个MessageQueue消息队列,Looper中保存一个消息队列,一个Looper唯一对应一个消息队列MessageQueue
        mThread = Thread.currentThread();//获取当前线程的实例
  }  

3、通过myLooper方法来获取当前线程对应的Looper实例

 public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//通过sThreadLocal中get方法获取当前主线程的Looper,因为Looper对象存储在sThreadLocal,为了当前线程绑定对应的Looper实例,因为可能其他线程也有自己的Looper
 }

三、启动Looper消息循环调用loop方法

执行到Looper.loop方法,主要是先拿到当前线程中的Looper实例,然后我们知道Looper实例中保存了一个唯一对应的消息队列MessageQueue. 然后从Looper实例中取消息队列,然后循环地通过MessageQueuenext方法取出消息Message,然后通过调用消息Message实例内部保存绑定的target(Handler对象)中的dispatchMessage方法来分发消息,并通过它的handleMessage方法处理消息以及最后对消息的回收recycle。

  public static void loop() {
        final Looper me = myLooper();//拿到当前主线程的Looper,从Looper中的sThreadLocal中获取,ThreadLocal可以保证looper实例是和当前线程绑定的
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//然后从looper中拿到消息队列MessageQueue
        ...
        //启动一个循环   
        for (;;) {
            Message msg = queue.next(); // 循环地调用MessageQueue的next方法,来取出队列中的消息,可能会阻塞
            if (msg == null) {//如果msg为null,说明队列已经退出,此时可以终止循环
                return;
            }
            ... 

            try {
                //取出Message消息实体与之绑定的Handler对象,并调用Handler对象的dispatchMessage方法进行分发消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...
            //回收当前已经分发处理过的Message实体以便于复用
            msg.recycleUnchecked();
        }
    }

四、Handler对象的创建

Handler构造器中会先去获取Looper实例,因为需要去Looper中取出MessageQueue实例,然后利用Handler发送消息Message,并把Message插入到MessageQueue中。

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }

    public Handler(Looper looper) {
        this(looper, null, false);
    }

    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

    public Handler(boolean async) {
        this(null, async);
    }

    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();//如果外部没有指定传入looper,就去获取当前线程的Looper实例
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//然后从mLooper中取出MessageQueue来初始化mQueue
        mCallback = callback;//初始化创建Handler对象构造器传入的callback,在Handler调用dispatchMessage方法内部会触发
        mAsynchronous = async;
    }

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

五、使用Handler发送消息Message

Handler发送消息主要分为两大类: 调用sendMessage方法传入Message实体、调用post方法传入一个Runnable任务。

    //通过直接发送一个Message实体
    public final boolean sendMessage(Message msg)
    public final boolean sendEmptyMessage(int what)
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) 
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) 
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) 

    public final boolean sendMessageAtFrontOfQueue(Message msg)

    public final boolean executeOrSendMessage(Message msg)

//post发送一个Runnable Callback, 其实最终也是包装成一个Message实体发送出去,因为Message实体中可以保存一个Runnable任务
   post(Runnable r)
   postAtTime(Runnable r, long uptimeMills)
   postAtTime(Runnable r, Object token, long uptimeMillis)
   postDelayed(Runnable r, long delayMills)
   postDelayed(Runnable r, Object token, long delayMillis)
   postAtFrontOfQueue(Runnable r);

1、Handler中sendMessage方式发送Message

 //第一步: 调用Handler中的sendMessage
 public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
 }

 //第二步: 调用Handler中的sendMessageDelayed
 public final boolean sendMessageDelayed(Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }

 //第三步: 调用Handler中的sendMessageAtTime
 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {//消息队列MessageQueue为null,抛出异常
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        //调用Handler中的enqueueMessage方法
        return enqueueMessage(queue, msg, uptimeMillis);
  }

//第四步: 调用Handler中的enqueueMessage方法
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//Message在插入到MessageQueue中之前,先给每个Message中target初始化为当前Handler对象,以此来完成每个消息Message与之对应处理消息的Handler绑定,用于执行Looper.loop中的msg.target.dispatchMessage方法的hanlder来分发消息。
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //最后将Message插入到MessageQueue中
        return queue.enqueueMessage(msg, uptimeMillis);
    }

2、Handler中post(Runnable)方式分发消息

 //第一步:调用Handler的post方法
 public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
 }

//第二步:调用getPostMessage方法,将一个Runnable包装成一个Message
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();//通过Message的obtain从Message池中复用一个Message实体,
        m.callback = r;//Message实体内部callback用于保存一个Runnable,这个callback在Handler调用dispatchMessage分发消息时,触发执行,且触发执行优先级优于创建Handler时传入的callback的触发。
        return m;
}
//第三步,就是与sendMessage方式同理调用sendMessageDelayed,最终调用Hanlder中的enqueueMessage方法

六、使用Handler分发消息(dispatchMessage)

Handler分发消息主要是通过Looper.loop方法中的msg.target.dispatchMessage(msg)

   public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//优先判断msg的callback是否为null,不为null就调用handleCallback,触发Message中的callback回调
            handleCallback(msg);
        } else {//msg中的callback为null
        //就继续判断创建Handler时,传入callback并保存在Handler的mCallback是否为null,
            if (mCallback != null) {
            //不为null触发传入的mCallback,执行其中的handleMessage回调方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //如果msg中的callback和mCallback都为null,就是执行handleMessage方法,一般用于Handler子类实现handleMessage,并触发子类中handleMessage实现
            handleMessage(msg);
        }
    }
    //handleCallback
    private static void handleCallback(Message message) {
        //取出Message中的callback(Runnable对象),触发执行它的run方法
        message.callback.run();
    }
     public void handleMessage(Message msg) {
     //do nothing,一般用于Handler子类重写
    }

下面用一张流程图表示分发流程:

七、Message消息实体的创建和回收

为了防止Message重复创建,在Message内部维护一个大小为50的消息池(单链表实现),可以通过obtain获取一个消息,如果消息池为空,就会fail back直接new一个消息实例,所以不建议直接自己手动创建一个消息实例,通过obtain直接获取更优雅;通过recycle或recycleUncheck方法回收消息。

1、Message消息获取

      public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;//取出消息池中的第一条消息Message
                sPool = m.next;//将sPool引用指针,指向第二条消息,也就是取出的Message的下一条消息m.next
                m.next = null;//断开当前消息与消息池链表的链,只需要把第一条Message的next为null
                m.flags = 0; // 重置消息Message正在被使用的标记
                sPoolSize--; //消息池大小递减
                return m;
            }
        }
        return new Message();//如果消息池中为null,那么直接failback到直接通过new方法创建一个Message实例。
    }

消息池链表获取消息数据结构原理图:

2、Message消息回收

  public void recycle() {
        if (isInUse()) {//如果当前还在使用中,强制回收会抛出异常
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }


    void recycleUnchecked() {
        flags = FLAG_IN_USE;//重置正在使用标识
        //重置Message中数据状态
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;//先将当前消息next指向sPool,实际就是把Message的next指向sPool,然后移动sPool指向当前Message,当前消息Message就成了池子中第一条消息,相当于在链表头部插入
                sPool = this;
                sPoolSize++;//消息池大小递增
            }
        }
    }

消息池链表插入消息数据结构原理图:

八、消息队列MessageQueue的消息的入队(enqueueMessage)和出队(next)

1、MessageQueue的创建

 MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();//nativeInit方法是native层实现,mPtr保存了NativeMessageQueue指针
 }

2、enqueueMessage-消息入队列

3、next-消息出队列

消息获取的链表数据结构原理图


   转载规则


《Android中消息机制与Handler源码解析》 mikyou 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Android中IntentService源码解析 Android中IntentService源码解析
Android中IntentService源码解析一、IntentService的介绍 IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,所以一般情况下我们会它的子类来实现,它一般用于后台耗时的
2019-12-29
下一篇 
Android中的ArrayMap源码解析 - Android - 面试 - 框架源码解析 Android中的ArrayMap源码解析 - Android - 面试 - 框架源码解析
Android中的ArrayMap源码解析一、概述ArrayMap实现Map<K,V>接口,所以它也是一个关联数组和哈希表。存储是key-value结构形式的数据。所以它也是线程不安全,可以允许key,value都为null.
2019-12-29