handler 的使用
//使用匿名内部类创建handler
public static Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
};
};
//构建消息
Message message = Message.obtain();
message.what = 1;
//发送消息
handler.sendMessage(message);
//延时发送消息
handler.sendMessageDelayed(message,1000);
//直接处理
handler.post(new Runnable() {
@Override
public void run() {
}
});
分析1:(创建handler
)
@Deprecated
public Handler() {
this(null, false);
}
public Handler(@Nullable Handler.Callback callback, boolean async) {
...
//获取当前线程的Looper
mLooper = Looper.myLooper();
//如果没有looper直接抛出异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// Looper.myLooper()作用:获取当前线程的Looper对象;若线程无Looper对象则抛出异常
// 即 :若线程中无创建Looper对象,则也无法创建Handler对象
// 故 若需在子线程中创建Handler对象,则需先创建Looper对象
// 注:可通过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象
// 2. 绑定消息队列对象(MessageQueue)
mQueue = mLooper.mQueue;
// 获取该Looper对象中保存的消息队列对象(MessageQueue)
// 至此,保证了handler对象 关联上 Looper对象中MessageQueue
mCallback = callback;
mAsynchronous = async;
mCallback = callback;
mAsynchronous = async;
}
分析二(创建Looper)
private static void prepare(boolean quitAllowed) {
// 1. 判断sThreadLocal是否为null,否则抛出异常
//即 Looper.prepare()方法不能被调用两次 = 1个线程中只能对应1个Looper实例
// 注:sThreadLocal = 1个ThreadLocal对象,用于存储线程的变量
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 2. 若为初次Looper.prepare(),则创建Looper对象 & 存放在ThreadLocal变量中
// 注:Looper对象是存放在Thread线程里的
// 源码分析Looper的构造方法->>分析a
sThreadLocal.set(new Looper(quitAllowed));
}
@Deprecated
public static void prepareMainLooper() {
//创建looper
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private Looper(boolean quitAllowed) {
// 1. 创建1个消息队列对象(MessageQueue)
// 即 当创建1个Looper实例时,会自动创建一个与之配对的消息队列对象(MessageQueue)
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
// 在Android应用进程启动时,会默认创建1个主线程(ActivityThread,也叫UI线程)
// 创建时,会自动调用ActivityThread的1个静态的main()方法 = 应用程序的入口
// main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象
public static void main(String[] args) {
...
Looper.prepareMainLooper();
// 1. 为主线程创建1个Looper对象,同时生成1个消息队列对象(MessageQueue)
// 方法逻辑类似Looper.prepare()
// 注:prepare():为子线程中创建1个Looper对象
ActivityThread thread = new ActivityThread();
// 2. 创建主线程
Looper.loop();
// 3. 自动开启 消息循环 ->>下面将详细分析
throw new RuntimeException("Main thread loop unexpectedly exited");
}
分析三(Looper.loop实现消息循环)
public static void loop() {
final Looper me = myLooper();
//先看有么有looper,没有直接抛异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
me.mInLoop = true;
//获取MessageQueue
final MessageQueue queue = me.mQueue;
...
//死循环去获取MessageQueue里边的消息
for (;;) {
//获取Message 有可能阻塞在这里
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
//分发消息 msg.target是一个Handler
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
//释放消息占据的资源
msg.recycleUnchecked();
}
}
@UnsupportedAppUsage
Message next() {
...
// 该参数用于确定消息队列中是否还有消息
// 从而决定消息队列应处于出队消息状态 or 等待状态
//如果等于-1表示没有消息
int nextPollTimeoutMillis = 0;
//for循环
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
//取出下一条消息
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//延时的处理,计算定时唤醒时间
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
//4.获取到一条消息,因为是消息队列是链表结构,所以需要调整一下链表
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
// 若 消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
// 下次循环时,消息队列则处于等待状态
nextPollTimeoutMillis = -1;
}
...
//5.这里提到 IdleHandler,是个什么东西?下面会分析
//在获取不到message的时候才会走的代码,也就可以理解为 IdleHandler是消息队列空闲(或者主线程空闲)时候才会执行的Handler。
//IdleHandler 是一个接口,只有一个方法 queueIdle() ,调用addIdleHandler(IdleHandler handler) 这个方法的时候会将handler添加到list中
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
分析四(处理消息)
//分发消息
public void dispatchMessage(Message msg) {
// 1. 若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息
// 则执行handleCallback(msg),即回调Runnable对象里复写的run()
// 上述结论会在讲解使用“post(Runnable r)”方式时讲解
if (msg.callback != null) {
//当使用handler.post()的时候会调用该方法
//因为msg自带一个callback
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 2. 若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息(即此处需讨论的)
// 则执行handleMessage(msg),即回调复写的handleMessage(msg) ->> 分析3
handleMessage(msg);
}
}
/**
* 分析3:handleMessage(msg)
* 注:该方法 = 空方法,在创建Handler实例时复写 = 自定义消息处理方式
**/
public void handleMessage(Message msg) {
... // 创建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) {
// 1. 将msg.target赋值为this
// 即 :把 当前的Handler实例对象作为msg的target属性
msg.target = this;
// 请回忆起上面说的Looper的loop()中消息循环时,会从消息队列中取出每个消息msg,然后执行msg.target.dispatchMessage(msg)去处理消息
// 实际上则是将该消息派发给对应的Handler实例
// 2. 调用消息队列的enqueueMessage()
// 即:Handler发送的消息,最终是保存到消息队列
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 判断消息队列里有无消息
// 1. 若无,则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态,则唤醒
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 {
// 2.否则插到链表中间,需要移动链表
// 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;
}
总结
1.在应用启动的时候,也就是ActivityThread的main方法里面,创建了Looper和MessageQueue,然后调用Looper.loop 开启消息循环
2.消息循环是这样的,调用MessageQueue的next方法,循环从消息队列中取出一条消息,然后交给Handler去处理,一般是回调handleMessage方法,取不到消息就阻塞,直到下一个消息入队或者其它延时消息到时间了就唤醒消息队列。
3.消息入队,通过调用handler的sendMessage方法,内部是调用MessageQueue的enqueueMessage方法,进行消息入队,入队的规制是:队列没有消息,或者要入队的消息没有设置delay,或者delay时间比队列头的消息delay时间短,则将要入队的消息放到队列头,否则就插到队列中间,需要移动链表。