Android 中的 Handler 同步分割栏实现方法
程序员文章站
2022-05-01 17:53:48
handler异步实现控制message的处理的,异步线程可以在handler中设置异步卡子,设置好了以后,当前handler的同步message都不再执行,直到异步线程将卡子去掉。
一、posts...
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中还有这个方法,获取消息队列中的下一个messageif (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++层,下次再研究下。