原文链接:
https://segmentfault.com/a/1190000004866028
https://www.jianshu.com/p/f70ee1765a61
Handler定义
Handler是Android一套非阻塞消息传递机制/异步通信机制
Handler存在意义
在Android中,为了UI操作是线程安全的,规定了只允许UI线程更新 Activity里的UI组件,主线程不能进行耗时操作,否则会阻塞线程,产生ANR异常,所以常常把耗时操作放到其它子线程中进行。但在实际开发中,存在多个线程并发操作UI组件的情况,导致UI操作的线程不安全,所以保证多个线程可并发操作UI组件的同时,线程是安全的。
Handler基本用法
android.os.Handler handler = new Handler(){
@Override
public void handleMessage(final Message msg) {
//这里接受并处理消息
}
};
//发送消息
handler.sendMessage(message);
handler.post(runnable);
通过实例化一个Handler重写handleMessage方法,然后在需要发消息的时候调用handler对象的send以及post系列方法,并且支持发送延时消息,handler发送消息的方法:
sendMessage(Message msg)
sendMessageDelayed(Message msg, long uptimeMillis)
post(Runnable r)
postDelayed(Runnable r, long uptimeMillis)
sendMessageAtTime(Message msg,long when)
sendEmptyMessage(int what)
sendEmptyMessageDelayed(int what, long uptimeMillis)
sendEmptyMessageAtTime(int what, long when)
单看基本用法是不是很简单,那网上说的跟handler相关的MessageQueue、Looper呢?并没有看到它们的身影呢?别慌,我们下面从源码一点一点分析。
Handler源码分析
1、首先我们先从Handler发送消息切入,以sendMessage为例,看下handler是如何把消息入队的。
// Handler类相关方法
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 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);
}
...
//MessageQueue相关方法
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(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) {
// 消息顺序入队
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 消息插入队列,按照when进行比对
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
至此就完成了消息入队操作,值得注意的是,如果消息入队时,队列中有信息,就要进行插队操作,插队按照时间message#when来进行。
2、说完了消息是如何入队的,接下来我们来讲讲消息是如何出队的,还是从源码的角度进行分析。
// ActivityThread就是我们常说的主线程或UI线程,ActivityThread的main方法是整个APP的入口
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
//Looper类相关
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
...
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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;
}
// This must be in a local variable, in case a UI event sets the logger
...
// Handler target
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
//Handler类相关
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//Message类操作
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
以上部分就完成了消息出队操作:ActivityThread的main()调用Looper.loop(),Looper开始轮询,通过MessageQueue的next()方法,Looper获取到了message对象之后,调用msg.target.dispatchMessage(msg)进行消息分发处理。
3、讲完消息的入队出队操作,第三部分要讲的是 Handler,Looper,MessageQueue,Message是如何串联起来的。借用下面图来加深理解。
handler机制图.png
Handler 常见Q&A
Q:说一说Handler中涉及到哪些类,各自功能是什么 ?
A:handler 、looper 、message 、 MessageQueue主要是这4个,ThreadLocal是JDK本身自带类 并不是专门为handler设计的。
handler是主线程与子线程之间通信的媒介,也是消息的主要处理者。它的作用是将message对象发送到MessageQueue中,也负责Looper分派过来的消息处理。
Looper是消息队列(Message Queue)与处理者(Handler)的通信媒介,负责从MessageQueue中不断轮询取出队列消息,将消息发送给对应的处理者handler。
MessageQueue是负责存储handler发送过来的消息,存储特点是 先进先出。
message是线程间通信的数据单元,即handler接受&处理的对象,存储需要操作的通信信息。
Q:MessageQueue 中的 Message 是有序的吗?排序的依据是什么
A:是有序的,排序的依据是 Message#when字段,该值是SystemClock#uptimeMillis() 与 delayMillis之和表示一个相对时间,该值是由 MessageQueue#enqueueMessage(Message, Long)方法设置的。
Q:子线程中可以创建Handler吗?
A:答案是可以的,前提是需要先创建Looper对象
Looper.prepare();
Handler handler = new Handler();
// ....
// 这一步可别可少了
Looper.loop();
Q:Handler 是如何与 Looper 关联的?
A:我们直接调用无参构造方法时会有一个自动绑定过程
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());
}
}
//就是这里 Looper跟Handler进行了绑定
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;
}
Q:Looper 是如何与 Thread 关联的?
A:Looper 与 Thread 之间是通过 ThreadLocal 关联的,这个可以看 Looper#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));
}
Q:Handler 有哪些构造方法?
A:Handler的构造方法可以传参数类型为 :Looper、Handler$Callback,现在我们就可以算出有多少个公共构造方法了:无参、单Looper、单Callback、Looper和Handler,共4种。
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
Q:looper为什么调用的是Handler的dispatchMessage方法?
A:我们看下dispatchMessage方法
// Handler.java:97
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从上面的代码不难看出有两个原因:
- 当
msg.callback != null时会执行handleCallback(msg),这表示这个 msg 对象是通过handler#postAtTime(Runnable, long)相关方法发送的,所以 msg.what和 msg.obj 都是零值,不会交给Handler#handleMessage方法。 - Handler可以接受一个
Callback参数,类似于 View 里的 OnTouchListener ,会先把事件交给Callback#handleMessage(Message)处理,如果返回 false 时该消息才会交给Handler#handleMessage(Message)方法。










网友评论