Android分析主线程与子线程,以及子线程之间相互通信

今天有兴趣研究了一下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 style="white-space:pre">	</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

这几行代码要注意一下,第一行获取了一个looper对象,第二行中的mCallback是Callback类型的,并且根据looper对象获取到了MessageQuene消息队列。CallBack是定义在Handler中的一个接口:
 
  
  public interface Callback {
        public boolean handleMessage(Message msg);
    }
这个就是我们new Handler之后重写的handlemessage方法来处理接收到的消息。Handler是通过这几个方法来发送消息的:
<span style="white-space:pre">		public final boolean sendMessage(Message msg)</span>
 <span style="white-space:pre">		public final boolean sendEmptyMessage(int what)</span>
<span style="white-space:pre">		public final boolean sendEmptyMessageDelayed(int what, long delayMillis) </span>
<span style="white-space:pre">		public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)</span>
<span style="white-space:pre">		public final boolean sendMessageDelayed(Message msg, long delayMillis)</span>
<span style="white-space:pre">		public final boolean sendMessageAtFrontOfQueue(Message msg)</span>
<span style="white-space:pre">		public final boolean sendMessageDelayed(Message msg, long delayMillis)</span>
这几个方法最终都调用的是<span style="font-family: Arial, Helvetica, sans-serif;">sendEmptyMessageAtTime(int what, long uptimeMillis)</span>这个方法。该方法的源码如下:
<span style="white-space:pre"></span><pre name="code" class="java"> <span style="white-space:pre">	</span> public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
       <span style="white-space:pre">		</span> MessageQueue queue = mQueue;
        <span style="white-space:pre">		</span>if (queue == null) {
          <span style="white-space:pre">		</span>  RuntimeException e = new RuntimeException(
                   <span style="white-space:pre">	</span>this + " sendMessageAtTime() called with no mQueue");
            <span style="white-space:pre">		</span>Log.w("Looper", e.getMessage(), e);
            <span style="white-space:pre">		</span>return false;
       <span style="white-space:pre">		</span> }
       return enqueueMessage(queue, msg, uptimeMillis);
    }

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

 
  
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre"></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 style="white-space:pre"></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 style="white-space:pre">	</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;">
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值