线程间通讯机制的内部实现原理,即Handler
、Message
、MessageQueue
、Looper
、HandlerThread
、AsyncTask
类的实现以及之间的关系。
当实例化一个Handler对象时,就完成了Handler实例与一个线程和一个消息队列的绑定。
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* 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);
}
public Handler(Callback callback, boolean async) {
······
//获取Looper对象
mLooper = Looper.myLooper();
······
//获取消息队列实体
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
问题: 为什么说一个线程对应一个Looper实例?
分析: 查看Looper.myLooper()源码
//-------------------ThreadLacal类----------------------
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal sThreadLocal = new ThreadLocal();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();//获得当前线程的Looper实例。
}
这个类实现了一个线程的本地存储,即每个线程都会有自己的内存空间来存放线程自己的值。
同时,所有的线程都共享一个ThreadLocal对象,但是不同的线程会有对应不同的value,且单独修改某一个线程值时不影响其它线程值,并支持null值。
小结: 每个线程都会存放一个独立的Looper实例,通过ThreadLocal.get()方法,就会获得当前线程的Looper实例。
问题: Handler是如何发生Runnable的呢?
分析:
//-------------------Handler类-------------------
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; //将Runnable对象当作msg中的callback属性传入;
return m;
}
小结: 其实传入的Runnable对象都是封装到Message类中。
问题: 那么Message中存放哪些信息呢?
分析: Message.obtain()是获取断掉的Message链关系的第一个Message。
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
static final int FLAG_IN_USE = 1 << 0;
static final int FLAG_ASYNCHRONOUS = 1 << 1;
static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
int flags;
long when; //向Handler发送Message生成的时间
Bundle data; //在Bundler对象上绑定要在线程中传递的数据
Handler target; //处理当前Message的Handler对象
Runnable callback;
Message next; //当前Message对下一个Message的引用
private static final Object sPoolSync = new Object();
private static Message sPool; //有下一个Message引用的Message链(Message池)
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
}
问题: Handler是如何发生Message的呢?
分析:
//-------------------------Handler类----------------------------
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// this代表Handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
小结: 当按时间发送时,无论是发送Message还是Runnable,最终调用的都是sendMessageAtTime()方法,里面的核心方法是enqueueMessage()方法,该方法就是调用MessageQueue中的enqueueMessage()方法,其实就是将Message加入到消息队列中。
问题: 如果发送消息只是将消息加入到消息队列中,那谁来把消息分发到Handler中呢?
分析:
//------------------------Looper类---------------------------
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//获取一个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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//消息轮询器
for (;;) {
//获取消息队列中下一个消息
Message msg = queue.next(); // might block
//判断是否获取到消息,如果没有消息,则阻塞;
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//消息分发 handler.dispatchMessage(msg),将消息从轮询器中取出发送到对应的handler中
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();//释放消息占据的资源
}
}
//----------------------Handler类---------------------------
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
//msg.callback其实就是传入的Runnable对象;
if (msg.callback != null) {
//如果handler传入的值是Runnable,则直接执行callback回调
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//Callback接口,具体业务处理在这里执行
handleMessage(msg);
}
}
小结:
在Looper类的loop()方法中调用Handler的dispatchMessage(msg)方法,在dispatchMessage(msg)内部最终调用了handlerMessage(msg)。
换句话说,Looper.loop()方法就是取得当前线程中的MessageQueue实例,然后不断循环获取消息,并将消息分发到对应的Handler实例上。
实质上只要调用Looper.loop()方法,就可以执行消息分发。
整个机制实现原理流程:
当应用程序运行时,会创建一个Linux进程和一个UI线程(ActivityThread),这个类里有一个main方法,是Java程序运行最开始的入口。
//-----------------------ActivityThread类---------------------------
public static void main(String[] args) {
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);
Process.setArgV0("");
//由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
//创建主线程
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//获取MessageQueue实例,执行消息分发
Looper.loop()
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread() {
...省略代码...
}
小结: UI线程一执行就已经调用了loop消息分发,所以当在UI线程中通过Handler对象发送消息或者任务时,会把Message加入到MessageQueue消息队列中,然后分发到Handler的handlerMessage方法里。
问题: 如何实现子线程之间的线程通信?
分析: 其实就是在子线程中实现handler.handleMessage()方法的调用。
//----------------------Thread类----------------------------
public Thread(String threadName) {
if (threadName == null) {
throw new NullPointerException("threadName == null");
}
//创建一个子线程
create(null, null, threadName, 0);
}
//--------------------------HandlerThread类-------------------------------
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name); //调用Thread(String threadName)
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
//Initialize the current thread as a looper.
Looper.prepare();
synchronized (this) {
//实例化Looper对象
mLooper = Looper.myLooper();
notifyAll();//Object类中的本地方法(native)
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//内部实现消息分发功能
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* Quits the handler thread's looper.
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
小结: 通过查看HandlerThread源码,发现HandlerThread继承自Thread类,从run()方法中可以发现,HandlerThread要调用start()方法,才能实例化HandlerThread的Looper对象和实现消息分发功能。
所以,要使用HandlerThread,必须先运行HandlerThread,这样才能取出对应的Looper对象,然后使用Handler(Looper)构造方法实例化Handler(即实现Handler和Looper的关联),这时handler就可以再子线程中执行handlerMessage()方法了。
自身继承Thread,是一个子线程;
与Handler+Message+Thread的区别:HandlerThread类里面处理Message消息可以是耗时操作,但是不能对UI操作,即handleMessage()方法只能在子线程中执行;
例子:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HandlerThread mThread = new HandlerThread("myThread");
//先调用start(启动一个线程
mThread.start();
//调用Handler(Looper)方法实例化一个Handler对象
myHandler myHandler = new myHandler(mThread.getLooper());
Message msg = myHandler.obtainMessage();
//把Message发送到目标对象,目标对象就是生成msg的目标对象。
msg.sendToTarget(); //实际上方法内部调用handler.sendMessage(msg);
}
class myHandler extends Handler {
//必须调用Handler(Looper looper)方法
public myHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
Log.e("这是新线程", ">>>>>>>新线程的测试");
}
}