Android消息机制

来源:互联网 发布:java中compare to 编辑:程序博客网 时间:2024/06/16 02:14

好多东西都忘了,看过的源码得记录一下,今天就来分析Andorid消息机制的源码。

Android消息机制主要涉及:

Handler、Looper、MessageQueue、Message、ThreadLocal

它们之间的关系如下所示:
这里写图片描述

有几个疑问:

 1. 在哪发消息? 2. 消息发到哪里去了? 3. 消息最后怎么被处理了? 4. 怎么就把在子线程发的消息变换到了主线程? 5. 上面各个类都是什么作用呢?

Android消息机制在实际开发中的应用

正式开始之前,先看一个Handler在多线程中具体使用的案例:

一个很简单的需求:点击页面上的按钮后更新TextView的内容。public class HandlerActivity extends AppCompatActivity {    private UpdateHandler handler;    private TextView tv;    static class UpdateHandler extends Handler{        private WeakReference<HandlerActivity> mHandlerActivity;        public UpdateHandler(HandlerActivity handlerActivity) {            this.mHandlerActivity = new WeakReference<HandlerActivity>(handlerActivity);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            HandlerActivity handlerActivity = mHandlerActivity.get();            if (handlerActivity != null){                handlerActivity.tv.setText((String)msg.obj);            }        }    }    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        init();        onLoad();    }    private void init() {        setContentView(R.layout.activity_handler);        tv = (TextView) findViewById(R.id.tv);        handler = new UpdateHandler(this);    }    private void onLoad(){        new Thread(){            @Override            public void run() {                super.run();                try{                    Thread.sleep(4000);                }catch (Exception e){                    e.printStackTrace();                }                Message msg = new Message();                msg.what = 1;                msg.obj = "加载完成";                handler.sendMessage(msg);            }        }.start();    }    @Override    protected void onDestroy() {        super.onDestroy();        handler.removeCallbacksAndMessages(null);    }}

在主线程创建一个Handler,然后开启一个工作线程待工作线程休眠4000毫秒后,发出一个Message然后在主线程更新TextView的内容。

消息机制源码分析

结合上面的例子,下面就挨个把这些问题搞明白:

在子线程中发出的消息,通过如下代码:

Message msg = new Message();msg.what = 1;                 //Message标识msg.obj = "加载完成";          //要传输的信息handler.sendMessage(msg);

追踪sendMessage的源码:

handler.sendMessage(message);

发现经过一串的调用sendMessage->sendMessageDelayed->sendMessageAtTime,最后走到了sendMessageAtTime这个方法中。

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

sendMessageAtTime中将Message入队,也就是放入到MessageQueue,MessageQueue是一个由链表实现的消息队列。

发送一个Runnable过程:

    public final boolean post(Runnable r) {        return sendMessageDelayed(getPostMessage(r), 0);    }
    //该方法把Runnable转换成Message    private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }

接下来走到sendMessageDelayed,以Message的方式继续处理

在sendMessageAtTime中调用了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);}

而真正的入队操作则到了MessageQueue中,代码如下:

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

看到prev=p、p = p.next、msg.next=p、prev.next=msg, 这不就是链表吗?所以MessageQueue是以单链表的形式来存储Message

到此为止:

消息已经发出去了,也存到了MessageQueue中等待被处理了,那么问题来了: 1. MessageQueue是被谁处理的? 2. 被怎么处理的?

这个时候Looper就隆重登场了!

在主线程中创建了我们的Handler

handler = new UpdateHandler(this);

追踪源码,此处调用的是Handler默认的构造方法,源码如下:

 /**     * Default constructor associates this handler with the {@link Looper} for the     * current thread.     * <p>     * If this thread does not have a looper, this handler won't be able to receive messages     * so an exception is thrown.     */    public Handler() {        this(null, false);    }

注释告诉我们:

默认的构造方法已经关联了一个当前线程的Looper如果是我们自己启动的线程,不自己准备Looper的话就会抛出异常:Can’t create handler inside thread that has not called Looper.prepare() 

接下来调用:

public Handler(Callback callback, boolean async) {        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;}

在主线程启动的时候,已经为我们准备了一个默认的主线程使用的Looper,在ActivityThread中,有如下代码:

public static void main(String[] args) {        ......        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        ......}

其中的两句代码,就可以帮我们揭秘——上面提到的两个问题:

MessageQueue中的消息是被谁处理的?
怎么被处理的?

其中的代码:

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

这就是为什么,我们在Activity中的OnCreate方法中创建了Handler但是并没有调用Looper.prepre()和Looper.loop()但是没问题的原因,使用的是主线程Looper。

下面看看两个方法,先看看prepareMainLooper:

    //为当前线程创建一个Looper,Android环境已经为你准备好了,不需要再调用这个方法。     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)方法:

 private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        //创建一个Looper,并设置给ThreadLocal        sThreadLocal.set(new Looper(quitAllowed)); }

ThreadLocal:现场内部的数据存储类,以线程为单元存储数据,此处在每个现场里都存了Looper。

很好奇new Looper(quitAllowed)这句代码做了什么,点击去看看:

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

一个private方法,我们无法new出一个Looper来,其中包含一个MessageQueue和当前的线程!因为当前线程是主线程,所以MessageQueue,Looper都是在主线程中。

在prepareMainLooper方法的最后,调用了myLooper()方法:

/** * 返回当前线程关联的Looper对象,如果当前线程没有关联Looper对象那么就返回null.*/public static @Nullable Looper myLooper() {        return sThreadLocal.get();}

至此,Looper.prepare()方法分析完毕,已经为主线程准备好了Looper。

接下来看,Looper.loop()方法:

  /**  *  轮询当前线程的消息队列。在轮询完成之后确保调用了quit()方法。  */  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;        ......        //死循环        for (;;) {            Message msg = queue.next(); // 可能会阻塞,从MessageQueue中获取下一个消息            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }           ......            try {                //msg.target 就是Handler,从MessageQueue中获取到的Message,被分发给了Handler中的dispatchMessage方法                msg.target.dispatchMessage(msg);            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }           ......        }    }

在Looper.loop()方法中,我们找到了答案:

阻塞式的获取消息队列中的Message。然后,调用Handler中的dispatchMessage进行Message的分发。

下面看看dispatchMessage的代码:

     /**     * 在这儿处理系统Message     */    public void dispatchMessage(Message msg) {        if (msg.callback != null) {   //处理runnable            handleCallback(msg);        } else {            if (mCallback != null) { //new Hanlder(CallBack)处理callBack                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);     //处理message        }    }

接下来子类实现handlerMessage方法来处理消息:

     /**     * 子类应该实现这个方法,来接收消息     */    public void handleMessage(Message msg) {    }

最后消息,在子类的handlerMessage方法中被处理了!

处理Runnable:

    private static void handleCallback(Message message) {        message.callback.run();    }

Message数据结构:

    public class Message{           Handler target;           Runnable callback;    }

这样Android中的消息机制的源码就分析完毕了,下面来回答刚开始提出的问题!
问题揭秘

1. Message在哪儿发出的

在子线程中发出的消息,通过如下代码:

Message msg = new Message();msg.what = 1;msg.obj = "加载完成";handler.sendMessage(msg);

2. Message发到哪儿去了?

Message发送到了MessageQueue中,一个消息队列中!单链表的形式存储数据

3. Message最后怎么被处理的?

Message被Looper的Loop方法从MessageQueue中借助next()方法取出,分发给Handler中的dispatchMessage方法,进行处理。这是一个典型的生产者、消费者模型!

4. 怎么就把子线程发出的消息变换到了主线程中?

子线程把Message发送到了MessageQueue中,MessageQueue在Looper中初始化,Looper在主线程中,所以MessageQueue也在主线程中,消息就这样被变换到了主线程中。

5. 上面各个类都是什么作用呢?

Handler:发送消息、处理消息
Looper:消息泵,用来从MessageQueue中读取消息
MessageQueue:消息队列,存储Message。内部用链表实现
Message:主线程和子线程之间的通信载体
ThreadLocal: 线程内部的数据存储类,在指定的线程中存储数据,以线程为单元。

Handler在什么线程中创建,Handler就在什么线程,Looper、Message也在该线程工作。UI线程默认有Handler、Looper,并开启了消息循环;在子线程中默认没有Looper,需要创建Looper,并开启消息循环,方式如下:

Looper.prepare();     //创建Looper,Looper以线程为单元hanlder = new Hanlder();Looper.loop();       //开启消息循环

至此,Android消息机制的源码就分析完毕!