在学习Android过程中,Android的消息机制是必须需要掌握的。楼主也只能算是一个Android的初学者,对Android的消息机制掌握的也不算很好。这里记录一下我自己对Android消息机制的理解,错误之处,希望各位指正。
  本文参考文章:
  1.Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
  2.Android应用程序消息处理机制(Looper、Handler)分析

1.概述

  要讲消息处理机制,不得不讲的就是Handler、Looper、MessageQueue这个重量级的人物。在这里对他们做一个概述,待会会详细的介绍他们。
  从大体上来说,Handler的主要作用就是发送Message和处理Message;Looper的作用就是不断从MessageQueue(消息队列)中取Message,然后交给Handler处理;MessageQueue存放由Handler发送的Message。通常来说,Message里面就是需要主线程执行的操作,比如,我们从网络获取的文字内容信息,需要显示到TextView上面去。

2.Handler

  首先我们从上面走下去,从Handler开始走。
  通常来说,使用Handler来处理异步消息,有基本的步骤。这里做一个简单的例子,在线程中发送一条String,让TextView来显示。

    private Button mButton = null;    //创建一个Handler的对象,注意我们重写了handleMessage消息    //handleMessage方法就是用来处理我们发送的消息    private Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            mButton.setText(msg.obj.toString());        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mButton = (Button) findViewById(R.id.button);        mButton.setOnClickListener(this);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.button: {                sendMessage();                break;            }        }    }    private void sendMessage() {        new Thread(new Runnable() {            @Override            public void run() {                //创建一个Message的对象                Message message = Message.obtain();                message.obj = "我被点击了";                //发送消息                mHandler.sendMessage(message);            }        }).start();    }

  上面代码中,我相信不难吧。现在我们需要理解的是Handler是怎么将一个Message从子线程传递到主线程中,然后执行的!

(1).sendMessage方法

  我们需要理解其中的缘由,我们来sendMessage方法的代码。

    public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }

  我们在一步一步的跟踪下去,最终到了enqueueMessage方法中

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

  其中,这个方法的三个参数,queue表示message需要进入的消息队列,msg就是我们之前创建的Message对象,uptimeMillis表示延迟时间。延迟时间这里不重要,我们先不看。
  我们从源代码中可以看出,首先msg.target = this。这句话将一个handler赋值到message的target属性,这一步非常重要,后面需要用的。这里我们先记住,这里的意思就是,表示当前的这个message属于哪个handler,因为有可能有很多的handler都在发送消息!
   mAsynchronous我们不看,这里不重要。最后是调用了queue.enqueueMessage(msg, uptimeMillis)方法,从这个方法的字面意思中,我们就可以看出来,这个方法是将一个message添加到queue的消息队列。
  我们先不看queue里面的代码。我们先来总结我们得到的信息。

  1.我们在子线程中发送一个Message,最终会进入到一个queue的消息队列中去。
  2.在Message进入消息队列之前,使用target字段来标记了当前的Message是哪个Handler发送的。

  到这里,我们好像没有收获,不急,我们来看看在构造一个Handler的时候,给我们创建那些东西!

(2).Handler的构造方法

  Handler的构造方法最终调用到了Handler(Callback callback, boolean async)方法里面。

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

  在Handler的构造方法中,我们发现了几个小细节,mLooper、mQueue都被赋值了。Looper我们待会讲,我们在调用sendMessage方法的时候,发现其中调用到这一步:

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

  我们注意到的是,之前的enqueueMessage里面的queue就是mQueue。
  到这里,我们知道了:

  1.Handler在创建的时候,会创建一个MessageQueue和一个Looper,也就是说,一个Handler同时绑定一个MessageQueue和一个Looper。
  2.我们在调用sendMessage等方法来发送消息的时候,消息进入的消息队列就是发送消息的Handler自己的MessageQueue。

2.Looper

  记得在概述中描述,Handler是发送消息和处理消息,现在我们对发送消息有了一个简单的认识,但是我们对处理消息没有介绍。不急,要想知道处理消息,我们必须先知道,消息是怎么被获取出来的,难道是Handler直接伸手从MessageQueue中去拿吗?怎么可能这么简单吗?接下来,我们介绍一下Looper,又一位重量级的人物

(1).Looper构造方法

  我们先来看看Looper的构造方法

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

  我们在这个构造方法里面发现,Looper创建一个MessageQueue。但是除了这个信息,似乎没看其他有用的信息了。
  怎么办?通常来说使用Looper不会直接的创建,从这里我们也看到它的构造方法是private的,而是调用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));    }

  在prepare方法中,需要注意的是:sThreadLocal变量是一个ThreadLocal变量。这种类型的变量有什么呢?具体的解释大家可以到网上去找(其实我也不是很懂,哈哈!!!)。这里简单的解释一下,ThreadLocal里面封装了一个变量,用来存储相应的信息,关键是不同的线程从ThreadLocal里面获取的变量是不同的,每个线程从ThreadLocal获取的是自己的变量,线程之间的是不会相互影响。
  从这里,我们可以得到是,每个线程都会有一个自己的Looper对象。
  到这里,我们知道:

  1.Looper的对象不能直接new,而是调用静态方法prepare方法来创建
  2.同一个线程不能调用两次prepare方法,因为Looper对象保存在一个ThreadLocal对象。
  3.从之前的Handler中,我们可以看到Handler里面持有了一个Looper对象(通过调用方法mLooper = Looper.myLooper())。这个对象就是TreadLocal封装的对象。从而得出,如果这个Handler在主线程中创建的,那么Looper肯定在属于主线程。

  从上面的结论中,我们可以得出,如果我们在一个线程中创建一个Handler,必须先创建当前线程的Looper对象。但是我们,你会发现,之前那个例子中,我们直接在一个Activity中创建一个Handler对象,而没有创建主线程的Looper,这个为什么没有报错呢?我们可以假设,我们在创建Handler时,主线程的Looper早已经被prepare了!但是具体在哪里调用的呢?待会我们会展示!

(2).loop方法

  在之前说过,Looper的作用就是不断从MessageQueue(消息队列)中取Message,然后交给Handler处理。但是我们到现在还不知道Looper到底是怎么从MessageQueue里面去消息的,这个就得引出我们的loop方法。
  我们先来看看loop方法的源代码,没有贴出完整的代码,而是删除了一些自己认为不重要的代码:

    public static void loop() {         //取得当前线程的Looper--还记得我们之前的说的ThreadLocal变量,这个变量里面保存的就是当前线程的         //Looper对象        final Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        //获取当前Looper的消息队列对象        final MessageQueue queue = me.mQueue;       // 死循环        for (;;) {            //如果没有消息的话,当前线程会被阻塞住,            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            final long end;            try {                //将当前的Message分发到Message自己的Handler                msg.target.dispatchMessage(msg);                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            msg.recycleUnchecked();        }    }

  我们先来整理一下,这个方法主要描述内容:

  1.首先获取当前线程的Looper对象和MessageQueue对象
  2.从MessageQueue里面去获取Message;如果获取到Message,则分发到Message自己的Handler去处理;反之,没有获取到信息,线程会被阻塞在next方法里面。
  3.通过Handler的dispatchMessage方法将获取的到Message从MessageQueue传递到了Handler,让Handler去处理。

  到这里,我们来整理一下思路。首先,在主线程创建了一个Handler,表示当前的Looper是放在主线程中的,当然MessageQueue也是属于主线程的。这里需要说明的是,就是一个线程只能有一个Looper,由于MessageQueue在Looper里面,所以MessageQueue也是只有一个,但是一个线程中Handler可以会被多次创建,所以,属于同一个线程的Handler中持有的是同一个MessageQueue和Looper。
  我们使用在主线程中创建的Handler通过调用sendMessage等方法来发送消息,最终进入的消息队列是主线程的MessageQueue。我们在Looper的loop方法中获取Message,然后将Message分发到Message的target,也就是发送Message的Handler,让它来处理。
  整个消息传递的过程就是这样的,这个就能解释,为什么我们在子线程中发送一个Message,在主线程的Handler能接收得到,从而进行对消息处理。因为Handler本身就是属于主线程,包括Handler里面持有的Looper和MessageQueue都是属于主线程。
  这里有一个疑问,那就是,我们知道我们在主线程中创建Handler时,其实主线程的Looper早就已经创建好了,这一点是怎么看出来得呢?
  例如:

        new Thread(new Runnable() {            @Override            public void run() {                //这里将Looper的prepare方法注释了                //表示当前的线程Looper没有被初始化//                Looper.prepare();                Handler mHandler = new Handler(){                    @Override                    public void handleMessage(Message msg) {                        Log.i("pby123", msg.obj.toString() + " " + Thread.currentThread().getName());                    }                };                Message message = Message.obtain();                message.obj = "pby123";                mHandler.sendMessage(message);            }        }).start();

  然后我们来运行一下程序,会发现一个臭名昭著的异常!



  这个异常我们应该不陌生,因为凡是要使用Looper的地方,都用check一下Looper是否preapre完成。
  上面的样例,我们是从一个新的线程里面创建Handler,由于是新的线程,就必须将这个线程的Looper和MessageQueue创建好。
  从而得出,我们在主线程中可以直接创建Handler,表示主线程的Looper和MessageQueue在我们创建Handler之前就已经创建完毕了!
  那到底是在哪里创建主线程的Looper。这个得引出ActivityThread类的main方法,我们都知道main方法是Java程序的入口,我们来看看main方法:

    public static void main(String[] args) {        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        SamplingProfilerIntegration.start();        // CloseGuard defaults to true and can be quite spammy.  We        // disable it here, but selectively enable it later (via        // StrictMode) on debug builds, but using DropBox, not logs.        CloseGuard.setEnabled(false);        Environment.initForCurrentUser();        // Set the reporter for event logging in libcore        EventLogger.setReporter(new EventLoggingReporter());        // Make sure TrustedCertificateStore looks in the right place for CA certificates        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        TrustedCertificateStore.setDefaultUserDirectory(configDir);        Process.setArgV0("");        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();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

  是不是看到main方法就感觉非常的亲切,终于可以回到当初学习Java的时候了。我也是,看到main方法之后,感觉之前有好多的问题都解决了!
  在main方法里面,我们看到:Looper.prepareMainLooper();这一句话的意思就是初始化的主线程的Looper。从这里,我们知道了,为什么我们在主线程里面可以创建Handler,而不用去prepare Looper。
  同时,我们还注意的是,Looper.loop()。我们之前已经分析过了,loop方法主要是在MessageQueue里面去取消息来处理。由于这里是主线程的Looper,所以这里的loop方法是从主线程的MessageQueue里面取Message。
  之前,我们使用一个在主线程创建的Handler在一个子线程发送Message,最后发送到了主线程的MessageQueue。但是什么时候调用的loop呢?其实就是在main方法里面调用了的。
  同样的道理,如果我们在一个新的线程里面分别创建Handler、Looper、MessageQueue,当调用Handler的sendMessage方法来发送一条Message,在Handler的handleMessage方法是不会接收到这个Message对象,这个是由于Looper的loop方法启动,当前线程
  我们知道,loop方法是一个死循环,但是为什么不会导致应用ANR呢?(Application Not Response)。其实网络上有很多的解释,可能是自己太笨了,理解不了那些思路。下面将来结合Looper的loop方法和MessageQueue的部分方法来解释一下原因。

4.MessageQueue

  我们知道MessageQueue相当于是一个存放Message的容器,Handler往这个容器里面放入Message,Looper从这个容器取数据。我们先来看看存放数据的部分
  在Looper的loop方法里面有这么一句:

Message msg = queue.next(); // might block

  上面这一句,就是Looper从MessageQueue里面取Message的操作,我们注意一下官方的注释,这一句可能会导致阻塞!
  那么什么情况下会被阻塞呢?是不是当前MessageQueue为空的时候,会被阻塞呢?如果MessageQueue为空时,会被阻塞,这一句又是什么作用呢?

            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }

(1).next方法

  我们先来看看next方法,这里我先将next的所有代码贴出,然后一部分一部分的分析

    Message next() {        // Return here if the message loop has already quit and been disposed.        // This can happen if the application tries to restart a looper after quit        // which is not supported.        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) {                // Try to retrieve the next message.  Return if found.                final long now = SystemClock.uptimeMillis();                Message prevMsg = null;                Message msg = mMessages;                if (msg != null && msg.target == null) {                    // Stalled by a barrier.  Find the next asynchronous message in the queue.                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                    if (now < msg.when) {                        // Next message is not ready.  Set a timeout to wake up when it is ready.                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        // Got a message.                        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 {                    // No more messages.                    nextPollTimeoutMillis = -1;                }                // Process the quit message now that all pending messages have been handled.                if (mQuitting) {                    dispose();                    return null;                }                // If first time idle, then get the number of idlers to run.                // Idle handles only run if the queue is empty or if the first message                // in the queue (possibly a barrier) is due to be handled in the future.                if (pendingIdleHandlerCount < 0                        && (mMessages == null || now < mMessages.when)) {                    pendingIdleHandlerCount = mIdleHandlers.size();                }                if (pendingIdleHandlerCount <= 0) {                    // No idle handlers to run.  Loop and wait some more.                    mBlocked = true;                    continue;                }                if (mPendingIdleHandlers == null) {                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];                }                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);            }            // Run the idle handlers.            // We only ever reach this code block during the first iteration.            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);                    }                }            }            // Reset the idle handler count to 0 so we do not run them again.            pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered            // so go back and look again for a pending message without waiting.            nextPollTimeoutMillis = 0;        }    }

  首先,我们来看看这一句话

            nativePollOnce(ptr, nextPollTimeoutMillis);

  根据Android应用程序消息处理机制(Looper、Handler)分析中介绍,nativePollOnce方法是用来表示当前线程会被阻塞,nextPollTimeoutMillis表达的意思就是当前的线程需需要阻塞多久。其中如果nextPollTimeoutMillis为0,表示不阻塞;-1表示无限期的阻塞,除非有线程唤醒它;其他的正数值表示阻塞多久。
  然后我们来看看下面的代码

                if (msg != null) {                    if (now < msg.when) {                        // Next message is not ready.  Set a timeout to wake up when it is ready.                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        // Got a message.                        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 {                    // No more messages.                    nextPollTimeoutMillis = -1;                }

  其中,msg表示当前的消息队列中第一个可以用的Message。其中先判断了当前的时间与消息执行的时间的大小,如果表示当前的时间小于Message执行的时间,也就是说,还没有到达该Message执行的时间,因此给nextPollTimeoutMillis赋值,表示线程要阻塞多久。
  但是,如果当前的时间符合Message的执行时间了,就得马上返回这个Message,去执行里面的操作。
  如果当前取得的第一个Message是空的,表示当前的MessageQueue里面没有了Message了,所以将nextPollTimeoutMills重置为-1,表示当前将无限期的阻塞下去,除非其他的线程将唤醒!
  其中我们还需要注意的是:

                if (mQuitting) {                    dispose();                    return null;                }

  这个return是整个next方法里面第二个return null,还记得我们在loop方法里面的一段代码吗?就是如果从next方法里面获取的方法是null的话,那么直接退出了loop循环。这个return null的返回条件就是就能解释我们之前的那个疑问--如果MessageQueue为空时,会被阻塞,这一句又是什么作用呢?
  第一个return null的条件是mPtr等于0时,关于mPtr等于0是表示什么情况,我也不是清楚,大概应该说,当前的MessageQueue对头的地址吧,这个只是我的猜测不一定正确!
  还是来看看第二个return null的条件吧,从中可以知道只有当mQuiting为true,才能返回 null。从这个变量名,我们可以知道,当这个MessageQueue正在quit时,会返回null。也就是说,当MessageQueue要被回收时,Looper会退出它的loop死循环。其他的情况下,loop都是在进行死循环的。
  但是,在哪一种情况下MessageQueue会被回收呢?我们发现MessageQueue的quit方法是默认修饰符,也就是说,只能在相同的包下,这个方法才能被调用!在我们的应用程序代码中是不能直接调用的,那哪里可以调用了quit方法呢?我们在Looper的quit方法里面找到了答案:

    public void quit() {        mQueue.quit(false);    }

  我们知道,每一个Looper对象是被放在了一个ThreadLocal变量中,也就是说,在哪个线程调用Looper的quit方法,就是quit哪个线程的MessageQueue,从而退出这个Looper的loop循环。
  例如:

    private void sendMessage() {        new Thread(new Runnable() {            @Override            public void run() {                Looper.prepare();                Handler handler = new Handler(){                    @Override                    public void handleMessage(Message msg) {                        Log.i("pby123", (msg.obj) + "");                    }                };                Message message = Message.obtain();                message.obj = "我是Message";                handler.sendMessageDelayed(message, 2000);                Looper.loop();                Log.i("pby123", "123");            }        }).start();    }

  上面的代码中,我们在一个新的线程里面创建了一个Handler、Looper,然后使用Handler发送了一个消息,最后将调用Looper的loop方法,让这个Looper活起来!然后我们来看看log:



  我们会发现,123这个log始终没有打印出来,也就是说,根本没有执行到这一句话,从而推出此时Looper的loop方法还在执行,当然如果没有消息的话,应该是被阻塞住了。这个现象间接的证明了,我们对源码的理解!
  这里需要注意的是,在同一个线程中,代码不能这样写:

        new Thread(new Runnable() {            @Override            public void run() {                //这里将Looper的prepare方法注释了                //表示当前的线程Looper没有被初始化                Looper.prepare();                Handler mHandler = new Handler() {                    @Override                    public void handleMessage(Message msg) {                        Log.i("pby123", (msg.obj) + "");                    }                };                                Looper.loop();                Message message = Message.obtain();                message.obj = "我是Message";                mHandler.sendMessageDelayed(message, 2000);                Log.i("pby123", "123");            }        }).start();

  这样写的话,loop一直在执行,根本不能执行到loop的代码!
  从而得知:

  1.除主线程之外,所有线程的Looper的loop方法不会自动调用,尽管我们调用Handler发送消息的相关方法。只有当我们在线程中明确调用loop方法,才会进行loop的循环。
  2.loop方法是一个死循环,它不断的从MessageQueue里面去拿Message。只有当取出的Message为null时,loop的死循环才能被结束。
  2.在MessageQueue的next方法里面,如果取出的Message的执行时间大于当前的时间的话,当前线程就会被阻塞相应的差值时间。但是如果当前的MessageQueue为空的话,那么就会当前的线程就会被无限期的阻塞。
  3.如果当前的MessageQueue被调用了quit方法,Looper的loop方法从MessageQueue里面取出的是null,从而导致Looper的loop方法执行完成。
  4.MessageQueue的quit方法不能被直接调用,而是通过Handler的quit来间接实现的!

  到这里,我们可以知道,为什么loop方法不会导致ANR。这是因为loop不是一直执行,而是当前MessageQueue里面有Message时,才会不断的去获取Message;如果MessageQueue是空的话,线程会被阻塞,只有当消息的时候才会被唤醒,loop方法才算是又活起来了!

(2).enqueueMessage方法

  说实话,next方法真的不是很好的理解,特别是结合了Handler、Looper之后!但是,我们最终还是对next有了一个大概的理解,我可不敢说深入的理解,哈哈!因为自己本来就是一个菜鸡!
  对next方法有了一个大概的理解,那么理解enqueueMessage方法应该不是很难的!先来看看enqueueMessage方法的代码:

    boolean enqueueMessage(Message msg, long when) {        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;    }

  上面的代码中,我删除了部分我认为不重要的代码。这个方法非常好理解,首先判断这个MessageQueue是否被标记为回收。如果被回收了的话,返回false,表示插入新的Message失败;其次如果没有被回收,那么插入将Message插入到正确的位置,这个正确的位置表示的是,按照Message的执行时间从小到大排序,时间最小的,放在队头!
  我觉得这里最重要的一步是这个:

            if (needWake) {                nativeWake(mPtr);            }

  如果当前需要唤醒的话,就去唤醒!

5.总结

  说实话,现在这篇文章写得差不多了,该写一个总结,将理解到的知识概括一下!

  1.在创建Handler之前,必须将当前线程的Looper线程创建完毕,也就是Looper的preapre方法必须放在Handler创建之前。之所以在线程中不用创建Looper,那是因为Google爸爸在ActivityThread的main方法里面已经给我们创建好了!
  2.Looper不会自动调用,必须在本线程中的最后一行代码来调用!因为一旦loop方法执行完毕,表示当前的线程即将执行完毕。这个可以参考ActivityThread的main方法代码!
  3.在调用Handler的发送Message的相关方法时,最终会将该Message放入与该线程绑定的MessageQueue里面。在放入Message,需要注意的是,Message本身带了when属性,这个表示Message时间,MessageQueue内部使用的这个When来排的序。
  4.在Looper的loop方法中,会不断的调用MessageQueue的next来获取一个Message。在获取Message时,要分为两种情况:1.Message不为null,那么就该Message分发到Message属于的那个Handler里面去消耗;2.如果为null的话,表示当前的MessageQueue已经被调用quit方法了,loop方法就会结束,整个线程就会结束!
  5.在MessageQueue的next方法里面,如果获取的Message执行时间大于当前的时间,表示还没有达到该Message的执行时机,于是让当前的线程阻塞相应的时间;如果获取的Message符合执行时机的话,那么立即返回;如果当前的MessageQueue为空了,立即阻塞当前的线程!

  最后,在结合的知识来解释一下,为什么我们在一个子线程中发送一个Message,主线程会被接受得到。
  首先,我们我们使用的是在主线程中创建Handler来发送Message,虽然说是在子线程发送Message,但是Message有一个target用来记录发送它的Handler。同时用于Handler在创建的时候,会持有当前线程的Looper和MessageQueue,所以这个Message最终还是发送了主线程的MessageQueue中。而在ActivityThread的main方法里面,主线程的Looper在不断的loop,所以不断的从自己线程的MessageQueue取Message来消耗,Message被获取之后,然后交给了target的handlerMessage方法去消耗,这个target就是在主线程我们自己创建的Handler。最终,我们就能知道为什么在子线程里面发送的Message能够到达主线程中的Handler

更多相关文章

  1. android的测试工具CTS
  2. Android菜单详解(二)——创建并响应选项菜单
  3. Android(安卓)网络协议
  4. Android(安卓)Studio更新升级方法
  5. android 实现 APP 保活且正常升级的方法
  6. Android(安卓)的消息队列模型
  7. android 进程与线程 - 开发文档翻译 - 进程
  8. 自定义View系列教程01--常用工具介绍
  9. Android(安卓)的消息队列模型

随机推荐

  1. Windows安装MySQL 5.7.18 解压版的教程
  2. 详解数据库连接的URL的写法及总结
  3. mysql5.7.19 winx64安装配置方法图文教程
  4. MySql超长自动截断实例详解
  5. mysql 5.7.15 安装配置方法图文教程(wind
  6. Mysql 5.6.37 winx64安装双版本mysql笔记
  7. centos6.5下mysql 5.7.19 安装配置方法
  8. mysql5.7.19 安装配置方法图文教程(win10
  9. mysql5.7.19 winx64解压缩版安装配置教程
  10. MySql安装与卸载的详细教程