Handler异步实现控制Message的处理的,异步线程可以在Handler中设置异步卡子,设置好了以后,当前Handler的同步Message都不再执行,直到异步线程将卡子去掉。
一、postSyncBarrier 设置同步卡
- 方法是隐藏的需要反射获取
- API版本<23方法位于Looper中,API版本>23位于
MessageQueue中 - 作用是为Handler设置卡子,过滤掉同步消息,同步消息等待执行
二、removeSyncBarrier 移除同步卡
- 方法是隐藏的需要反射获取
- API版本<23方法位于Looper中,API版本>23位于
MessageQueue中 - 作用是为Handler移除卡子,放开同步消息过滤,同步消息继续执行。
package qin.xue.imageviewscaletype.activity;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
import java.lang.reflect.Method;
import qin.xue.imageviewscaletype.R;
/**
* Created by qinxue on 2018/5/21.
*/
public class SyncBarrierActivity extends Activity {
private static final String TAG = "SyncBarrierActivity";
private Handler handler;
private Handler workHanlder;
private HandlerThread workHandlerThread;
private Method methodPostSyncBarrier;
private Looper looper;
private int token;
private int count = 0;
private long start = 0;
private long end = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sync_barrier_activity_layout);
workHandlerThread = new HandlerThread("work_thread");
workHandlerThread.start();
looper = workHandlerThread.getLooper();
workHanlder = new Handler(looper);
handler = new Handler();
workHanlder.post(runnable);
handler.post(new Runnable() {
@Override
public void run() {
start = System.currentTimeMillis();
Log.i(TAG, "设置同步卡 时间:" + start);
postSyncBarrier(); //设置同步卡
}
});
handler.postDelayed(new Runnable() {
@Override
public void run() {
end = System.currentTimeMillis();
Log.i(TAG, "移除同步卡 时间:" + end + "耗时:" + (end - start));
removeSyncBarrier(); //5秒后移除同步卡
}
}, 5000);
}
//postSyncBarrier 和 removeSyncBarrier 方法是否在MessageQueue类中(api23及以上)
private static boolean methodInQueue() {
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M;
}
private Runnable runnable = new Runnable() {
@Override
public void run() {
count++;
Log.i(TAG, "count: " + count + "time: " + System.currentTimeMillis()); //同步打印数据
workHanlder.postDelayed(runnable, 100);
}
};
/**
* 移除卡子
*/
private void removeSyncBarrier() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
removeSyncBarrier(looper.getQueue());
} else {
removeSyncBarrier(looper);
}
}
private void removeSyncBarrier(Object obj) {
try {
Method method = MessageQueue.class.getMethod("removeSyncBarrier", int.class);
method.invoke(obj, token);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 添加卡子
*/
private void postSyncBarrier() {
if (methodInQueue()) {
postSyncBarrier(looper.getQueue());
} else {
postSyncBarrier(looper);
}
}
private void postSyncBarrier(Object obj) {
try {
methodPostSyncBarrier = obj.getClass().getMethod("postSyncBarrier");
token = (int) methodPostSyncBarrier.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、结果展示
05-21 17:44:22.926 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 1time: 1526895862926
05-21 17:44:22.947 12715-12715/qin.xue.imageviewscaletype I/SyncBarrierActivity: 设置同步卡 时间:1526895862947
05-21 17:44:27.931 12715-12715/qin.xue.imageviewscaletype I/SyncBarrierActivity: 移除同步卡 时间:1526895867930耗时:4983
05-21 17:44:27.932 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 2time: 1526895867932
05-21 17:44:28.033 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 3time: 1526895868033
05-21 17:44:28.134 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 4time: 1526895868134
05-21 17:44:28.236 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 5time: 1526895868235
05-21 17:44:28.336 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 6time: 1526895868336
05-21 17:44:28.437 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 7time: 1526895868437
05-21 17:44:28.538 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 8time: 1526895868538
05-21 17:44:28.639 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 9time: 1526895868639
05-21 17:44:28.739 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 10time: 1526895868739
05-21 17:44:28.841 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 11time: 1526895868841
05-21 17:44:28.941 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 12time: 1526895868941
05-21 17:44:29.043 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 13time: 1526895869043
05-21 17:44:29.144 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 14time: 1526895869144
05-21 17:44:29.244 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 15time: 1526895869244
05-21 17:44:29.345 12715-12732/qin.xue.imageviewscaletype I/SyncBarrierActivity: count: 16time: 1526895869345
四、代码解释
- 代码中首先加了使用主线程设置异步线程workHandler中的异步卡子,导致workhandler中的Message不在执行,仅保留待执行。
- 然后在5s之后在主线程移除了异步线程workHandler中的卡子,workhandler中的Message继续执行下去。
五、源码分析
我这里是6.0的源码
postSyncBarrier
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
-这里可以看到这个卡子msg,新建了一个msg并根据时间插入到消息队列中,而且这个msg没有设置target
removeSyncBarrier
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
-(p.target != null || p.arg1 != token)这里如果arg1 == token或者target为null,那么这是一个卡子。需要移除掉 ,代码如下。 prev.next = p.next;
next()
- 在MessageQueue中还有这个方法,获取消息队列中的下一个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());
}
摘取部分代码,循环便利整个消息队列,如果target为null,那么直接利用isAsynchronous()找到下一个异步的message,跳过同步消息,设置执行时间。
大致就是这样。
Handler中还有阻塞机制
-如果发先下一条消息执行时间过长,会阻塞掉线程Looper循环的。在C++层,下次再研究下。