今天有兴趣研究了一下Android线程之间的通信,主要是通过Hanlder和looper,和messagequene来完成的。先来看一下子线程之间如何通过它们来实现。 子线程之间的通信我在查看了looper的源码最上面的注释中给出了使用的示例如下:



<pre name="code" class="java">** * Class used to run a message loop for a thread. Threads by default do * not have a message loop associated with them; to create one, call * {@link #prepare} in the thread that is to run the loop, and then * {@link #loop} to have it process messages until the loop is stopped. * * <p>Most interaction with a message loop is through the * {@link Handler} class. * * <p>This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * <pre> * class LooperThread extends Thread { * public Handler mHandler; * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * Looper.loop(); * } * }</pre> */





通过对该示例的分析,可知就是在子线程中定义handler对象通过它来发送消息,因此我写了一个小的demo,代码量不大就直接贴上了:



package com.example.testactivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.app.Activity; import android.content.Intent; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { public Handler handlerTwo; public Handler handlerOne; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { findViewById(R.id.id_btnOne).setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View arg0) { switch (arg0.getId()) { case R.id.id_btnOne: startThreadOne(); startThreadTwo(); break; default: break; } } /*** * 开启第一个Thread * */ private void startThreadOne() { oneThread mOneThread = new oneThread(); mOneThread.start(); } /** * 开启第二个线程 */ private void startThreadTwo() { twoThread mTwoThread = new twoThread(); mTwoThread.start(); } class oneThread extends Thread { @Override public void run() { int j = 0; Looper.prepare(); handlerOne = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 2) { System.out.println("线程1接受到来自线程2消息" + msg.what); } } }; for (int i = 0; i < 5000; i++) { j++; } if (j > 4000) { if (handlerTwo != null) { handlerTwo.sendEmptyMessage(1); } } Looper.loop(); } } class twoThread extends Thread { int m = 0; @Override public void run() { Looper.prepare(); handlerTwo = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); if (msg.what == 1) { System.out.println("线程2收到线程1发来的数据" + msg.what); } } }; for (int i = 0; i < 6000; i++) { m++; } if (m > 5000) { if (handlerOne != null) { <span > </span>handlerOne.sendEmptyMessage(2); } } Looper.loop(); } } }测试结果如下:






可以看出两个线程这之间完成了消息发送,但是之间具体是如何发送的。下面来查看一下Handler源码是如何完成消息的发送。首先看他的构造方法:



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 = Looper.myLooper();



mCallback = callback



mQueue = mLooper.mQueue






public interface Callback {
        public boolean handleMessage(Message msg);
    }
这个就是我们new Handler之后重写的handlemessage方法来处理接收到的消息。Handler是通过这几个方法来发送消息的:
<span >		public final boolean sendMessage(Message msg)</span>
<span >		public final boolean sendEmptyMessage(int what)</span>
<span >		public final boolean sendEmptyMessageDelayed(int what, long delayMillis) </span>
<span >		public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)</span>
<span >		public final boolean sendMessageDelayed(Message msg, long delayMillis)</span>
<span >		public final boolean sendMessageAtFrontOfQueue(Message msg)</span>
<span >		public final boolean sendMessageDelayed(Message msg, long delayMillis)</span>
这几个方法最终都调用的是<span style="font-family: Arial, Helvetica, sans-serif;">sendEmptyMessageAtTime(int what, long uptimeMillis)</span>这个方法。该方法的源码如下:
<span ></span><pre name="code" class="java"> <span >	</span> public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
       <span >		</span> MessageQueue queue = mQueue;
        <span >		</span>if (queue == null) {
          <span >		</span>  RuntimeException e = new RuntimeException(
                   <span >	</span>this + " sendMessageAtTime() called with no mQueue");
            <span >		</span>Log.w("Looper", e.getMessage(), e);
            <span >		</span>return false;
       <span >		</span> }
       return enqueueMessage(queue, msg, uptimeMillis);
    }

该方法判断了一下之前获取到的消息队列是否存在不存在跑出异常,存在又调用了enqueueMessage(queue, msg, uptimeMillis)这个方法,跟进看一下具体的代码:




<span style="font-family: Arial, Helvetica, sans-serif;"><span ></span></span><pre name="code" class="html">   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
通过调用参数MessageQuene对象的<span style="font-family: Arial, Helvetica, sans-serif;">enqueueMessage(msg, uptimeMillis);接着跟进去看一下:</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span ></span></span><pre name="code" class="java">   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("MessageQueue", 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;
    }




<span >	</span>前面是是一些异常处理之后,<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">是获得自身的同步锁synchronized (this),接着这个msg跟MessageQueue实例的头结点Message进行触发时间先后的比较,<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">如果触发时间比现有的头结点Message前,则这个新的Message作为整个MessageQueue的头结点,如果阻塞着,则立即唤醒线程处理<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">如果触发时间比头结点晚,则按照触发时间先后,在消息队列中间插入这个结点<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">接着如果需要唤醒,则调用nativeWake函数,至此Java层的代码结束。我一直在考虑到这儿我们的消息发送到哪儿了呢?且听下回分解</span></span></span></span>


<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"></span></span></span>
</pre><pre name="code" class="java" style="font-size: 18px;">