andorid状态机StateMachine

状态机的代码android并没有开放使用,在源码的frameworks/base/core/java/com/android/internal/util里StateMachine.java 、State.java 、IState.java,就这三个文件,看过源码后表示设计很精妙,必须记录下来。

一、状态机我的理解是是可以更根据当前的状态和外界的的信息输入,采取不同的对应和状态的切换。android的状态机使用如下;

继承StateMachine实现自己的状态机,在这里可继承State并自定义状态机的各状态,这里我自定义了S0,S1,S2,S3,S4,这样几个状态,在状态中重写processMessage处理当前状态下消息响应机制,我在这里只是重写了S3状态的,跳转到S2,在构造函数中使用addState函数,建立状态树,使用setInitialState初始化状态机的初使状态,start()使状态机运行。

具体使用不再写啦,源码分析以下省的忘记。

package com.example.qinxue.statemachinetest;

import android.os.Message;
import android.util.Log;

import com.example.qinxue.statemachinetest.util.State;
import com.example.qinxue.statemachinetest.util.StateMachine;

/**
 * Created by qinxue on 2017/9/5.
 */

public class MyStateMachine2 extends StateMachine {
    private static final String NAME = "qinxue_machine";
    private static final String TAG = "StateMachine_2";

    protected MyStateMachine2() {
        super(NAME);
        addState(s0, null);
        addState(s1, s0);
        addState(s2, s0);
        addState(s3, s1);
        addState(s4, s1);
        setInitialState(s3);
        start();
    }


    private S0 s0 = new S0();
    private S1 s1 = new S1();
    private S2 s2 = new S2();
    private S3 s3 = new S3();
    private S4 s4 = new S4();


    class S0 extends State {
        @Override
        public void enter() {
            Log.i(TAG, "S0 enter()");
            super.enter();
        }

        @Override
        public void exit() {
            Log.i(TAG, "S0 exit()");
            super.exit();
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.i(TAG, "S0 processMessage()");
            return super.processMessage(msg);
        }
    }

    class S1 extends State {
        @Override
        public void enter() {
            Log.i(TAG, "S1 enter()");
            super.enter();
        }

        @Override
        public void exit() {
            Log.i(TAG, "S1 exit()");
            super.exit();
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.i(TAG, "S1 processMessage()");
            return super.processMessage(msg);
        }
    }

    class S2 extends State {
        @Override
        public void enter() {
            Log.i(TAG, "S2 enter()");
            super.enter();
        }

        @Override
        public void exit() {
            Log.i(TAG, "S2 exit()");
            super.exit();
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.i(TAG, "S2 processMessage()");
            return super.processMessage(msg);
        }
    }

    class S3 extends State {
        @Override
        public void enter() {
            Log.i(TAG, "S3 enter()");
            super.enter();
        }

        @Override
        public void exit() {
            Log.i(TAG, "S3 exit()");
            super.exit();
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.i(TAG, "S3 processMessage()");
            transitionTo(s2);
            return true;
        }
    }

    class S4 extends State {
        @Override
        public void enter() {
            Log.i(TAG, "S4 enter()");
            super.enter();
        }

        @Override
        public void exit() {
            Log.i(TAG, "S4 exit()");
            super.exit();
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.i(TAG, "S4 processMessage()");
            return super.processMessage(msg);
        }
    }
}



二、源码分析

1、首先在构造中使用的函数 super(NAME);这一句分析以下源码干了啥?

protected StateMachine(String name) {
        // 创建HandlerThread
        mSmThread = new HandlerThread(name);
        mSmThread.start();
        Looper looper = mSmThread.getLooper();
        //
        initStateMachine(name, looper);
    }

创建了一个HandlerThread,其实就是有Looper的普通Thread,拿到了它的looper,貌似要初始化Handler什么的看一下initStateMachine这个方法。

 private void initStateMachine(String name, Looper looper) {
        mName = name;
        //建立消息处理Handler
        mSmHandler = new SmHandler(looper, this);

    }

这里初始化了SmHandler,一个自定义Handler,没错状态机信息就是用它发送的。

2、通过addState来创建状态树,类似数据结构树,树上全是状态机的状态,改变状态时就是在这颗树的树枝上爬过去的。查看一下代码

private final StateInfo addState(State state, State parent) {
            if (mDbg) {
                Log.d(TAG, "addStateInternal: E state=" + state.getName()
                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
            }
            StateInfo parentStateInfo = null;
            if (parent != null) {
                parentStateInfo = mStateInfo.get(parent);
                if (parentStateInfo == null) {
                    // Recursively add our parent as it's not been added yet.
                    parentStateInfo = addState(parent, null);
                }
            }
            StateInfo stateInfo = mStateInfo.get(state);
            if (stateInfo == null) {
                stateInfo = new StateInfo();
                mStateInfo.put(state, stateInfo);
            }

            // Validate that we aren't adding the same state in two different hierarchies.
            if ((stateInfo.parentStateInfo != null) &&
                    (stateInfo.parentStateInfo != parentStateInfo)) {
                throw new RuntimeException("state already added");
            }
            stateInfo.state = state;
            stateInfo.parentStateInfo = parentStateInfo;
            stateInfo.active = false;
            if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
            return stateInfo;
        }


StateInfo:保存了当前state节点,当前节点的父节点,和活动状态active这标记使在切换状态时用来爬树的,减少遍历。

mStateInfo:是hashMap保存状态节点和StateInfo,通过StateInfo可以找到父节点。

每调用addState()就往相应节点添加,根据我的代码建立如图树





setInitialState(s3);这一句代码,设定状态机的初始状态为s3,具体代码不贴了,start()之后,用红色表示节点标记为active为true,如下图。


之后我发送信息,切换状态到S2,这是S2向上便利,找到第一个红的节点(以activie来判断),这里是S0,用蓝色表示,之后按照下图的路径,红色执行exit(),蓝色执行enter(),最终切换到目标状态。s3.exit()->s1.exit()->s2.enter();




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值