Android定义的一套同进程中线程间的消息传递机制
通常用来把子线程中的UI更新消息,传递给主线程更新UI;当然也可以反过来使用,只是会麻烦一些。
Handler消息机制是由一组MessageQueue、Message、Looper、Handler共同组成的。
如果说Binder/socket是android必须掌握的IPC机制,那么Handler则是必须掌握的消息机制。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
// Step 1: 创建Handler
mHandler = new Handler() {
public void handleMessage(Message msg) {
//处理即将发送过来的消息
System.out.println("thread id="+Thread.currentThread().getId());
}
};
Looper.loop();
}
}
// Step 2: 创建并启动LooperThread线程,内部包含Looper
LooperThread looperThread = new LooperThread();
looperThread.start();
// Step 3: 发送消息
looperThread.mHandler.sendEmptyMessage(10);
可以看到,在子线程中使用Handler比在主线程中使用多了Looper.prepare();和Looper.loop();的步骤。这个之后在其他文章中叙述。
首先我们来看看经常用的有哪些异步方式。
Activity.java
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
看来还是Handler,如果是主线程则马上执行Run方法,如果不是继续看Handler的代码
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
postDelayed我们经常用,和post都是调用的sendMessageDelayed方法,只是延时为0而已
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
注意SystemClock.uptimeMillis()是开机到现在的时间
enqueue就是入队嘛
public Handler(@Nullable 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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
注意这个mQueue成员变量是在Handler构造函数中初始化的,从Looper来的
View.java
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().postDelayed(action, delayMillis);
return true;
}
可以看到View的post和postDelayed的方法都是走的一样的路子,也看到了Handler的出现,但是第二条路 简单地说一下吧,细节不在这儿一一贴出了。我们使用 View.post() 时,其实内部它自己分了两种情况处理,当 View 还没有 attachedToWindow 时,通过 View.post(Runnable) 传进来的 Runnable 操作都先被缓存在 HandlerActionQueue,然后等 View 的 dispatchAttachedToWindow() 被调用时,就通过 mAttachInfo.mHandler 来执行这些被缓存起来的 Runnable 操作。从这以后到 View 被 detachedFromWindow 这段期间,如果再次调用 View.post(Runnable) 的话,那么这些 Runnable 不用再缓存了,而是直接交给 mAttachInfo.mHanlder 来执行。
AsyncTask是一个轻量级的异步实现,可以轻松实现工作线程和UI线程的通信
他实现的原理也是 线程池 + Handler 具体怎么实现的去找源码吧
到这儿我们发现好像这些异步类\方法只要涉及到了与主线程做通信,都使用了Handler,这就可以回答刚才的拓展问题了,他是Android设计之初就封装的一套消息传递机制,不用它还真不行。