Android StateMachine总结(一)相关基础类

本文主要介绍了Android中的StateMachine,它是Android系统中用于状态管理的重要工具,常见于蓝牙、WiFi和telephony等领域。StateMachine的核心是SmHandler,所有关键方法都封装在其中。文章详细讲解了State、StateInfo和SmHandler的使用,包括状态的进入、退出、消息处理和状态切换的实现机制。此外,还探讨了如何构建状态树和设置初始状态,以及状态机的启动和运行过程。
摘要由CSDN通过智能技术生成

StateMachine总结(一)相关基础类

本篇StateMachine的总结均基于android7.0 wifi状态机。

什么是状态机?

  • StateMachine在我们Android系统中用途较广泛,包括蓝牙,wifi,telephony都有继承StateMachine实现自己的状态管理。

  • 什么是状态呢?

    状态是事物的一种属性,在一般情况下是指事物所表现出来的行为或形态。

    例:汽车(点火、行驶、故障、停车)
    
        水(液体、固体、气体)
    
  • android的状态机的的意义:

    对于接受到某个事件(消息)后,不同的状态下能做出不同的操作。
    
  • StateMachine中几乎所有重要的方法均封装在SmHandler中,所以SmHandler才是StateMachine的核心,StateMachine只是对SmHandler的再次封装。

State

 public class State implements IState {

   protected State() {
   }
   @Override
   public void enter() {
   }
   @Override
   public void exit() {
   }
   @Override
   public boolean processMessage(Message msg) {
       return false;
   }
   @Override
   public String getName() {
       String name = getClass().getName();
       int lastDollar = name.lastIndexOf('$');
       return name.substring(lastDollar + 1);
   }
}

1、State实现IState接口,自己写状态均要继承State类,即所有状态都是State的派生类。

2、 这是State封装的几个方法,enter()是在进入该状态时调用,常做一些准备工作。 exit()离开是调用,做善后工作。processMessage()的工作是,处于该状态时,接收到Msg做相应的处理,即前言里说到的:不同的状态下对相同的消息能做出不同的操作。一般自己写状态都会重写该方法。

StateInfo

private class StateInfo {

    State state;
    StateInfo parentStateInfo;
    boolean active;
} 

State表示该状态, parentStateInfo表示该状态的父状态, active表示该状态是否激活,enter()(进入该状态)为true, exit()(退出该状态)为false, 具体做何用,后面再看到,并详细解释。

###State与StateInfo的关系

 /** The map of all of the states in the state machine */
private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();

State和StateInfo以key和values的方式存在名为mStateInfo的HashMap中,每一个State对应一个StateInfo.

SmHander

SmHandler的主要功能有以下三个:

  1. 建立树形层次结构存储State;
  2. 状态机的建立和状态切换;
  3. 消息处理和派发。

###建立树形层次结构存储State
状态机对个状态以树的形式管理,实现自己的状态机第一步是要将状态建立好,然后通过addState(State state,State parent)方法将状态存到mstateInfo中,下面是该方法具体的实现,并对每行代码的注释:

private final StateInfo addState(State state, State parent) {        
	StateInfo parentStateInfo = null;       
	if (parent != null) {           
		parentStateInfo = mStateInfo.get(parent); //取出父节点的parentStateInfo信息     
		if (parentStateInfo == null) {  //如果父节点为null,则递归调用,把当前节点作为父节点      
			parentStateInfo = addState(parent, null);           
		}       
	}       
	StateInfo stateInfo = mStateInfo.get(state); //新节点,肯定为null
	if (stateInfo == null) {           
		stateInfo = new StateInfo();           
		mStateInfo.put(state, stateInfo); //将state和stateInfo放入hashMap中,后面根据state即可取出stateInfo信息     
	}      
	if ((stateInfo.parentStateInfo != null) && (stateInfo.parentStateInfo != parentStateInfo)) {  //新创建还没有赋值,肯定为null,否则抛出异常
		throw new RuntimeException("state already added");       
	}     
	stateInfo.state = state;       
	stateInfo.parentStateInfo = parentStateInfo;//以后通过state可以找到父节点,一直递归,如果state的父节点为null,则表示到了顶部       
	stateInfo.active = false; //时候是当前活动状态标志         
	return stateInfo;   
}

通过以上方法便达到建立状态树的目的,例如:
这里写图片描述

###状态机的建立和状态切换
状态树建立好之后,得设个初始状态,方法为setInitialState(State initialState), 该方法的很简单,只是将initialState赋值给mInitialState的变量。

初始状态设好后,状态机的准备工作完成,后面就是让状态机run起来,StateMachine提供了这个方法:

public void start(){

    /** Send the complete construction message */
	mSmHandler.completeConstruction();   
}

这个方法只是调了SmHandler的completeConstruction()方法,下面是该方法的具体实现的核心部分:

private final void completeConstruction() {
    int maxDepth = 0;
    … …
    mStateStack = new StateInfo[maxDepth];  
    mTempStateStack = new StateInfo[maxDepth];  //初始化这两个数组
    setupInitialStateStack(); 
    sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
}
  • setupInitialStateStack()这个方法的实现看后面,这里不好讲清楚。

  • sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj)), 这里发送SM_INIT_CMD的消息,这便是SmHandler的第三个功能。

消息处理和派发

状态机run起来,我们怎么通过状态机达到做事情的目的呢? 前面说State这个类时谈到重写processMessage()以对接收的的消息进行处理,比如我实现一个状态机MyStateMachine,肯定继承与StateMachine。

把MyStateMachine看做是server端,app看做是client端,client端怎么让server做事呢? – 发消息的方式。 当前状态会对消息做不同的处理。 StateMachine封装的方法:

消息的派发:
public final void sendMessage(Message msg) 
{

       // mSmHandler can be null if the state machine has quit.
       SmHandler smh = mSmHandler;
       if (smh == null) return;
       smh.sendMessage(msg);
   }

可以看到,仍然是通过SmHandler的sendMessage,所以,消息的接收处理也是在SmHandler的handleMessage(Message msg).

下面是handleMessage核心代码:

消息的处理:
public final void handleMessage(Message msg) {

   … … … 
    /** State that processed the message */
   State msgProcessedState = null;
   if (mIsConstructionCompleted) {
        msgProcessedState = processMsg(msg);
   } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
                && (mMsg.obj == mSmHandlerObj)) {
        /** Initial one time path. */
        mIsConstructionCompleted = true;
        invokeEnterMethods(0);
   } else {
        throw new RuntimeException("StateMachine.handleMessage: "
                   + "The start method not called, received msg: " + msg);
   }
   performTransitions(msgProcessedState, msg);
    … … …
}

其中重要的地方有三点:

  1. processMsg(msg):通过这个方法调用各个状态的重写的processMessage(), 设初始状态时,这里不调用,因为mIsConstructionCompleted此时为false;
  1. invokeEnterMethods(0):这个方法的触发条件是mMsg.what == SM_INIT_CMD, 这个msg只在设初始状态时接收到,所以,在设初始状态时会invokeEnterMethods(0),这个方法以后在每次状态切换的时候都用上,但只有这里的参数是0。
  1. performTransitions():这个是很重要的方法,状态切换其实是在这个方法里实现的,具体实现核心代码看下面:
private void performTransitions(State msgProcessedState, Message msg) {
	... ...
	State destState = mDestState;     
	if (destState != null) {       
		while (true) {   //从当前节点往上查找,将当前节点及active=false的父节点存在mTempStateStack中,直到找到active=true的父节点,并将其返回。
			StateInfo commonStateInfo =  setupTempStateStackWithStatesToEnter(destState);
	        invokeExitMethods(commonStateInfo);             
	        int stateStackEnteringIndex = moveTempStateStackToStateStack();
	        invokeEnterMethods(stateStackEnteringIndex);
	        moveDeferredMessageAtFrontOfQueue();             
	        if (destState != mDestState) { // A new mDestState so continue looping               
	            destState = mDestState;             
	        } else {              
	             break;             
	        }         
	    }         
	    mDestState = null;     
	}
     … …
} 

这里调用invokeExitMethods()和invokeEnterMethods()实现状态的进入和退出,做到状态的切换。

##END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值