Android 命令过滤

Android 命令过滤

在工作中遇到这样一个问题,当滑动 App 中的色盘时,被控制灯的颜色也要跟随变化。

最开始的做法是在 View 的 onTouch().ACTION_CHANGE 中直接调用发送命令给固件,然而由于 onTouch() 方法在单次滑动触发的 ACTION_CHANGE 事件过多,而固件那边的处理速度和资源有限,无法处理这么快的命令。这时就需要在 App 端做处理了。

处理思路:

要点:App 发送给设备的命令要是均匀的,还要保证最后的一个指令不能丢。

处理代码如下:

public abstract class AdvanceStrategy {

    public final static byte[] DEFAULT_SAMPLE_LIST = new byte[]{(byte) 0x01};

    private final static AdvanceStrategy DEFAULT = new DefaultAdvanceStrategy();
    private static AdvanceStrategy definition;
    protected Callback mCallback;
    protected int sampleRate = 200;
    protected byte[] sampleOpcodes;

    public static AdvanceStrategy getDefault() {
        synchronized (AdvanceStrategy.class) {
            if (definition != null)
                return definition;
        }
        return DEFAULT;
    }

    public static void setDefault(AdvanceStrategy strategy) {
        synchronized (AdvanceStrategy.class) {
            if (strategy != null)
                definition = strategy;
        }
    }

    static public boolean isExists(byte opcode, byte[] opcodeList) {
        for (byte opc : opcodeList) {
            if ((opc & 0xFF) == (opcode & 0xFF))
                return true;
        }

        return false;
    }

    final public int getSampleRate() {
        return sampleRate;
    }

    /**
     * 设置采样率,单位毫秒
     *
     * @param sampleRate
     */
    final public void setSampleRate(int sampleRate) {
        this.sampleRate = sampleRate;
    }

    /**
     * 回调接口,采样到的命令交由回调接口处理
     *
     * @param mCallback
     */
    public void setCallback(Callback mCallback) {
        this.mCallback = mCallback;
    }

    public byte[] getSampleOpcodes() {
        if (sampleOpcodes == null)
            return DEFAULT_SAMPLE_LIST;
        return sampleOpcodes;
    }

    /**
     * 设置采样的Opcode数组
     *
     * @param sampleOpcodes
     */
    public void setSampleOpcodes(byte[] sampleOpcodes) {
        this.sampleOpcodes = sampleOpcodes;
    }

    /**
     * 处理传进来的命令
     *
     * @param opcode     命令吗
     * @param address    目标地址
     * @param params     命令参数
     * @param delay      命令延时
     * @param tag        命令标签
     * @param noResponse 命令发送方式
     * @param immediate  是否立即写入底层FIFO
     * @return 命令是否成功写入
     */
    abstract public boolean postCommand(byte opcode, int address, byte[] params, int delay, Object tag, boolean noResponse, boolean immediate);

    /**
     * 启动,执行初始化
     */
    abstract public void onStart();

    /**
     * 停止,做一些清理工作
     */
    abstract public void onStop();

    public interface Callback {
        boolean onCommandSampled(byte opcode, int address, byte[] params, Object tag, int delay, boolean noResponse);
    }

    /**
     * 默认的命令发送策略
     */
    private static class DefaultAdvanceStrategy extends AdvanceStrategy {

        private static final int ACTION_SEND_COMMAND = 1;

        public final static String TAG = "AdvanceStrategy";

        private long lastSampleTime;

        /**
         * 记录是否是最后一条命令,避免之前发送过一条合法的命令,之后再发送一次被丢弃的命令
         */
        private boolean isLastCommand = true;

        public DefaultAdvanceStrategy() {
        }

        @Override
        public void onStart() {
            this.lastSampleTime = 0;
        }

        @Override
        public void onStop() {
        }

        @Override
        public boolean postCommand(byte opcode, int address, byte[] params, int delay, Object tag, boolean noResponse, boolean immediate) {
            long currentTime = System.currentTimeMillis();
            boolean flag = false;

            if (lastSampleTime == 0) {
                //第一个命令,直接写入FIFO
                lastSampleTime = currentTime;
                flag = true;
            } else if (immediate || !isExists(opcode, this.getSampleOpcodes())) {
                //立即发送的命令,不在采样列表中的命令直接发送
                flag = true;
            } else {
                //计算和最后一次采样时间的间隔,获取采样的命令
                long interval = currentTime - this.lastSampleTime;
                if (interval >= this.getSampleRate()) {
                    lastSampleTime = currentTime;
                    flag = true;
                    isLastCommand = true;
                }
            }

            if (flag && this.mCallback != null) {
                Log.d(TAG, "Sample Opcode : " + Integer.toHexString(opcode));
                //所有采样到的命令立即交给回调接口处理
                return this.mCallback.onCommandSampled(opcode, address, params, tag, delay, noResponse);
            } else {
                Log.d(TAG, "Miss Opcode : " + Integer.toHexString(opcode));
                isLastCommand = false;
                if (mCallback != null){
                    CommandBean commandBean = new CommandBean(opcode, address, params, tag, delay, noResponse);
                    sendMessageDelay(commandBean, ACTION_SEND_COMMAND);
                }
            }
            return false;
        }

        public void sendMessageDelay(Object object, int what) {
            mHandler.removeMessages(what);
            Message message = Message.obtain();
            message.what = what;
            message.obj = object;
            mHandler.sendMessageDelayed(message, getSampleRate());
        }

        class CommandBean {
            byte opcode;
            int address;
            byte[] params;
            Object tag;
            int delay;
            boolean noResponse;

            public CommandBean(){}

            public CommandBean(byte opcode, int address, byte[] params, Object tag, int delay, boolean noResponse) {
                this.opcode = opcode;
                this.address = address;
                this.params = params;
                this.tag = tag;
                this.delay = delay;
                this.noResponse = noResponse;
            }
        }

        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what){
                    case ACTION_SEND_COMMAND:
                        CommandBean commandBean = (CommandBean) msg.obj;
                        if (!isLastCommand && mCallback != null){
                            Log.i(TAG, "handleMessage() onCommandSampled code = " + commandBean.opcode);
                            mCallback.onCommandSampled(commandBean.opcode, commandBean.address, commandBean.params, commandBean.tag, commandBean.delay, commandBean.noResponse);
                        }
                        break;
                }
            }
        };
    }
}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页