Android系统中对于WIFI,蓝牙模块运用了状态机来管理状态。搜索了下4.0中的状态机有以下文件:

./frameworks/base/wifi/java/android/net/wifi/WpsStateMachine.java
./frameworks/base/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
./frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
./frameworks/base/core/java/android/net/dhcp/DhcpStateMachine.java
./frameworks/base/core/java/android/net/DhcpStateMachine.java
./frameworks/base/core/java/android/server/BluetoothAdapterStateMachine.java

以上的类都是继承于./frameworks/base/core/java/com/android/internal/util/StateMachine.java。

系统为了好管理,将一个模块的不同状态封装成State,而StateMachine就是用来管理这些State的。

看一下State类中提供的主要方法有:

@Override
public void enter() {
}

/* (non-Javadoc)
* @see com.android.internal.util.IState#exit()
*/
@Override
public void exit() {
}

/* (non-Javadoc)
* @see com.android.internal.util.IState#processMessage(android.os.Message)
*/
@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);
}

再回到StateMachine.java这个文件,在这个文件开始有一大堆的英文说明该类的作用和实现过程。下面结合自己的理解梳理下这段内容:


用法准备条件:首先根据需要要生成我们的State, 比如 private class PowerOff extends State{}(引用源代码中管理Bt的一个状态),我们定义的这个类必须继承State这个类并根据需要实现相应的方法,其中的processMessage这个方法必须实现(如果不重写这个方法,那我们的状态机将没有任何意义)。enter()方法是当我们进入该状态的时候第需要调用的(像程序代码中的构造函数),exit()是退出该状态的时候调用(像析构函数)。


当准备好State后,就在调用addState(State state, State parent)将我们的状态添加进StateMachine。


到这里首先看下StateMachine还有些什么内容。

内部类:SmHandler(大部分处理都是通过这个类完成),ProcessedMessageInfo,ProcessedMessages。在SmHandler中又包含内部类StateInfo,成员StateMachine(mSm),HashMap<State, StateInfo> mStateInfo,mStateStack,mDeferredMessages,State mInitialState, State mDestState, rivate ArrayList<Message> mDeferredMessages。

启动状态机的步骤:

1.首先需要通过addState添加上面准备好的State实例,每一个State都可以添加一个自身的State和一个parentState。add的方法最中是通过调用SmHandler的StateInfo addState(State state, State parent)方法。这个方法会将他的状态以及他的父状态的信息取出来并放到mStateInfo这个hashMap表中的(首先会从mStateInfo中通过State找一下是否存在该状态的相关信息,不存在才会put)。

2.添加完所有的状态后就调用setInitialState设置一个初始状态, 最终调用的是SmHandler的setInitialState给mInitialState赋值。

3当经过1,2步骤后就要调用StateMachine:start()函数启动状态机机,start函数最终调用的是SmHandler:completeConstruction ,这个函数主要是调用exit退出当前状态并更新记录的State的堆栈信息(mStateStack中的State)并掉用State的enter函数,正式进入新的状态。

4.当我们通过StateMachine:sendMessage发送消息的时候,StateMachine就会找到当前的State调用其processMessage来做相应的处理动作。如果当前状态在处理完相应的事务后需要切换到新的状态就需要调用transitionTo(IState destState)设置mDestState的值。

注意:上面说过一个State可能包含一个Parent State,如果在当前的State中没有能处理发送来的msg的时候,就要向上找其父State来处理,依次向上遍历,如果所有的State都不能处理的话就会调用SmHandler:unhandledMessage来处理。


另外两个方法:deferMessage和sendMessageAtFrontOfQueue,在代码中可以通过deferMessage向mDeferredMessages这种存放暂时不处理的消息。在每此处理完新旧状态更新的时候就要调用sendMessageAtFrontOfQueue将mDeferredMessages中的消息优先发送出去(有可能是在A状态deferMessage的消息,切换到B状态后才发送出去,此时就应该B状态去处理这个消息),每次发送完就会清空mDeferredMessages一次。


图表解释:

mP0

/ \

mP1 mS0

/ \

mS2 mS1

/ \ \

mS3 mS4 mS5---> initial state


如上图,添加了mS5至mP0的8个状态, 其中mS1是mS5的父状态,mP1是mS1的父状态,依次类推。上图可以看出mS5是初始状态,当启用状态机的收回调用StateMachine:start()----->SmHandler:completeConstruction(),这函数里面会调用invokeEnterMethods从而依次调用mP0--mP1--mS1--mS5的enter函数,并将他们每一个对应的StateInfo的active置为true。最后调用的是mS5,所以当前的状态进入mS5。此时如果外面有消息通过StateMachine:sendMessage发送进来,首先就会mS5----mP0依次调用processMessage的方法来出来当前消息直到处理成功(如果mS5就处理成功就跳出了,就不会进入mS1, 以此类推)。


假设现在mP0----mS5处理发送来的消息成功,并且transitionTo(mS4),往上遍历发现有共同祖先mP1,那么就会依次调用mS5---mS1的exit函数,依次调用mS2---mS4的enter函数从而进入mS4状态。现在处于active的状态就是mS4,mS2,mP1,mP0了,下次来消息的时候就该mS4来处理了。


StateMachine的基本原理就是这样,StateMachine基本线路就在SmHandler的中handleMessage函数。 下一篇将会结合蓝牙状态机的转换进行具体的介绍。
















更多相关文章

  1. C语言函数以及函数的使用
  2. Android 窗帘(Curtain Menu)效果五之应用场景和使用方法
  3. android 获取路径目录方法 以及 获取路径方法
  4. Linux系统下安装android sdk的方法步骤
  5. 选项卡使用方法二(Android学习随笔十三)
  6. 使用AndroidStudio编译NDK的方法及错误解决方式
  7. Android Studio 配置快捷方式生成JNI头文件的方法
  8. android 读取DDMS里的文件时打不开,解决方法
  9. Android:Manifest merger failed with multiple errors, see log

随机推荐

  1. 详细介绍JavaScript解析 JSON 及 XML的示
  2. Web设计中如何使用XML数据源对象详细介绍
  3. web.xml 组件加载顺序详解
  4. 详细介绍Spring使用多个xml配置文件的代
  5. 基于XML的桌面应用的图文代码详细介绍
  6. LINQ to XML 编程基础的图文代码详细介绍
  7. 详细介绍使用XML资源文件来定义颜色,样式
  8. 使用xmldom在服务器端生成静态html页面
  9. C#-XML操作类的代码实例详解
  10. 详细介绍Web安全之XML注入的示例代码