欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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中还有这个方法,获取消息队列中的下一个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++层,下次再研究下。