android状态机是线程么,安卓StateMachine运行过程理解(翻译)
最近研究了一下WifiStateMachine,发现它主要继承了StateMachine,这里根据StateMachine文件的英文文档进行翻译。
1. 这个State Machine是一个层级状态机
下面是我移动这个statemachine到安卓应用上面来进行调试的版本:
点击下载: 测试代码
2.每一个状态都是state结构体的一个子类实现
每个子类都必须实现state的processMessage函数,其余的enter/exit/getName是可选实现的。
enter/exit这种实现方式和面向对象的构造函数和析构函数很像。知道它的原理就行了。
3.状态机的创建
通过addState可以把所以状态和这个状态的依赖关系添加到状态机里面去。最终就会形成一个相互依赖的树结构。
然后再通过setInitialState设置状态机的初始状态。以后的状态机就从这里开始。
最后调用start函数启动状态机,这个方法会调用和当前状态有关的所有enter方法,而且调用顺序从第一个父节点开始,这个其实和面向对象的构造方法的调用很像。
比如说有如下的三个状态,
mP1
/ \
mS2 mS1 ----> initial state
那么这棵树需要这样来创建:
addState(mS2,mP1);
addState(mS1,mP1);
setInitialState(mS1);
start();
其中初始状态是mS1,调用start后
enter的调用顺序是mP1->enter();,mS1->enter();
4.状态机的转换
调用transitionTo函数用于状态机的转换。转换的过程中遵循如下的原则。
比较当前的状态的父状态是否和要切换的有一样的,如果有一样,假设他是mP1:就调用当前状态一直到mP1(不包括)的exit函数,然后再冲mP1到新状态的所有节点的enter.
比较当前的状态的父状态是否和要切换的有一样的,如果不一样,就调用当前状态的exit函数,以及其所有父状态的exit函数,然后再从新状态的第一个父状态的enter函数一直调用到当前状态enter。
5.消息处理
涉及到消息处理如果做过安卓应用的都知道有一个叫Handler的东西,这个东西会和一个线程结合起来工作。其实stateMachine的处理方法就用的这个机制。只不过进行了功能多的包装而已。
要给当前状态发送消息时只需要调用sendMessage就可以了,当然还要构造消息,这里用obtainMessage,其实这两个函数就是Handler的包装。
当消息发送后就会调用当前状态的processMessage函数,这里它有三种处理办法:
(1). 如果自己处理不了就返回false 或者 NOT_HANDLED.这样stateMachine就会去调用它的父亲的processMessage,直到处理成功或者最终都没有调用那么unhandledMessage()会被调用。
(2).如果所有的状态都完成了就会调用transitionToHaltingState,调用了它之后,所有的消息都由transitionToHaltingState来处理了。
(3).如果当前消息自己还是没法处理,需要切换到其他状态处理,那么它可以调用deferMessage这样可以把当前的消息保存直到状态切换后处理的第一个消息里面。
最后是谷歌的例子:
class Hsm1 extends StateMachine {
private static final String TAG = "hsm1";
public static final int CMD_1 = 1;
public static final int CMD_2 = 2;
public static final int CMD_3 = 3;
public static final int CMD_4 = 4;
public static final int CMD_5 = 5;
public static Hsm1 makeHsm1() {
Log.d(TAG, "makeHsm1 E");
Hsm1 sm = new Hsm1("hsm1");
sm.start();
Log.d(TAG, "makeHsm1 X");
return sm;
}
Hsm1(String name) {
super(name);
Log.d(TAG, "ctor E");
// Add states, use indentation to show hierarchy
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
// Set the initial state
setInitialState(mS1);
Log.d(TAG, "ctor X");
}
class P1 extends State {
@Override public void enter() {
Log.d(TAG, "mP1.enter");
}
@Override public boolean processMessage(Message message) {
boolean retVal;
Log.d(TAG, "mP1.processMessage what=" + message.what);
switch(message.what) {
case CMD_2:
// CMD_2 will arrive in mS2 before CMD_3
sendMessage(obtainMessage(CMD_3));
deferMessage(message);
transitionTo(mS2);
retVal = HANDLED;
break;
default:
// Any message we don't understand in this state invokes unhandledMessage
retVal = NOT_HANDLED;
break;
}
return retVal;
}
@Override public void exit() {
Log.d(TAG, "mP1.exit");
}
}
class S1 extends State {
@Override public void enter() {
Log.d(TAG, "mS1.enter");
}
@Override public boolean processMessage(Message message) {
Log.d(TAG, "S1.processMessage what=" + message.what);
if (message.what == CMD_1) {
// Transition to ourself to show that enter/exit is called
transitionTo(mS1);
return HANDLED;
} else {
// Let parent process all other messages
return NOT_HANDLED;
}
}
@Override public void exit() {
Log.d(TAG, "mS1.exit");
}
}
class S2 extends State {
@Override public void enter() {
Log.d(TAG, "mS2.enter");
}
@Override public boolean processMessage(Message message) {
boolean retVal;
Log.d(TAG, "mS2.processMessage what=" + message.what);
switch(message.what) {
case(CMD_2):
sendMessage(obtainMessage(CMD_4));
retVal = HANDLED;
break;
case(CMD_3):
deferMessage(message);
transitionTo(mP2);
retVal = HANDLED;
break;
default:
retVal = NOT_HANDLED;
break;
}
return retVal;
}
@Override public void exit() {
Log.d(TAG, "mS2.exit");
}
}
class P2 extends State {
@Override public void enter() {
Log.d(TAG, "mP2.enter");
sendMessage(obtainMessage(CMD_5));
}
@Override public boolean processMessage(Message message) {
Log.d(TAG, "P2.processMessage what=" + message.what);
switch(message.what) {
case(CMD_3):
break;
case(CMD_4):
break;
case(CMD_5):
transitionToHaltingState();
break;
}
return HANDLED;
}
@Override public void exit() {
Log.d(TAG, "mP2.exit");
}
}
@Override
void halting() {
Log.d(TAG, "halting");
synchronized (this) {
this.notifyAll();
}
}
P1 mP1 = new P1();
S1 mS1 = new S1();
S2 mS2 = new S2();
P2 mP2 = new P2();
}它所构造的树结构:
mP1 mP2
/ \
mS2 mS1
如果用下面的代码开始状态机:
Hsm1 hsm = hsm.makeHsm1();
synchronize(hsm) {
hsm.sendMessage(hsm.obtainMessage(hsm.CMD_1)); hsm.sendMessage(hsm.obtainMessage(hsm.CMD_2)); try { // wait for the messages to be handled hsm.wait(); } catch (InterruptedException e) { Log.e(TAG, "exception while waiting " + e.getMessage()); }}
最后输出:D/hsm1 ( 1999): makeHsm1 ED/hsm1 ( 1999): ctor ED/hsm1 ( 1999): ctor XD/hsm1 ( 1999): mP1.enterD/hsm1 ( 1999): mS1.enterD/hsm1 ( 1999): makeHsm1 XD/hsm1 ( 1999): mS1.processMessage what=1D/hsm1 ( 1999): mS1.exitD/hsm1 ( 1999):
mS1.enterD/hsm1 ( 1999): mS1.processMessage what=2D/hsm1 ( 1999): mP1.processMessage what=2D/hsm1 ( 1999): mS1.exitD/hsm1 ( 1999): mS2.enterD/hsm1 ( 1999): mS2.processMessage what=2D/hsm1 ( 1999): mS2.processMessage what=3D/hsm1 ( 1999):
mS2.exitD/hsm1 ( 1999): mP1.exitD/hsm1 ( 1999): mP2.enterD/hsm1 ( 1999): mP2.processMessage what=3D/hsm1 ( 1999): mP2.processMessage what=4D/hsm1 ( 1999): mP2.processMessage what=5D/hsm1 ( 1999): mP2.exitD/hsm1 ( 1999): halting
android状态机是线程么,安卓StateMachine运行过程理解(翻译)相关推荐
- android 模拟器声音设置,逍遥安卓模拟器运行游戏过程中没有声音怎么解决
有用户反映,使用逍遥安卓模拟器运行游戏过程中突然没有了声音,重新加载之后还是这样,这是为什么呢?针对这一问题,小编整理了具体的解决方法,大家可以学习保存. 逍遥安卓模拟器运行游戏过程中没有声音怎么解决 ...
- android状态机是线程么,[Android] 状态机 StateMachine 源码剖析
1. 案例 案例:我们常见的汽车,我们可以使用它行驶,也可以将它停止在路边.当它在行驶的过程中,需要不断的检测油量,一旦油量不足的时候,就将陷入停止状态.而停止在路边的汽车,需要点火启动,此时将检测车 ...
- android状态机是线程么,Java中的线程状态机 - java
有没有一种方法可以将线程保留在状态中等待更改? 我的意思是,等一下事情发生了(更改var,调用方法等). 也许它需要使用事件监听器或同步的对象/方法. 这样的状态机通常的方法 statemachine ...
- android 打开移动开关,教你一个让安卓手机运行更流畅的小技巧:打开这个开关即可...
原标题:教你一个让安卓手机运行更流畅的小技巧:打开这个开关即可 安卓用户对于"系统优化"这个词一定不会陌生,因为Android系统越用越卡的毛病难以解决,必须进行优化才能保持流畅. ...
- android AsyncTask 只能在线程池里单个运行的问题
android 的AysncTask直接调用Execute会在在一个线程池里按调用的先后顺序依次执行. 如果应用的所有网络获取都依赖这个来做,当有一个网络请求柱塞,就导致其它请求也柱塞了. 在3.0 ...
- win10系统.android是什么文件夹,d盘文件不见了怎么恢复?Windows10增加安卓程序运行...
原标题:d盘文件不见了怎么恢复?Windows10增加安卓程序运行 d盘文件不见了怎么恢复?windows电脑我们很多人都在用,但是大家知道D盘文件删除了怎么恢复吗?其实很多人不知道,先给大家介绍一下 ...
- windows i0s android,更多阅读:Win10是咋运行安卓/i0S应用的
更多阅读:Win10是咋运行安卓/i0S应用的 北风吹!夜凄凉!问题不解心慌慌,一问易答来帮忙,不用谢我我姓王. 夜风中一个悲戚的声音划破天际,天空飘来十二个大字,正是"听说只要发帖小编就会 ...
- Android:Socket客户端开发,Android 的Socket客户端优化,Android非UI线程修改控件程序崩溃的问题
一.Android:Socket客户端开发 创建一个工程 我们要做的是按下按键之后,去往服务器 (服务器) 或者我们自己写的服务器 ,给他发送一些预定好的东西 然后打开操作界面 然后修改一下 你要发送 ...
- ncnn填坑记录八:将自己训练的模型打包为APK并部署到安卓端运行
上一篇:ncnn填坑记录七:examples/squeezenet.cpp代码阅读 做一个分类任务,模型选取的mobilenetv3,训练好模型,并按前文依次转换为onnx.ncnn后,参考官方htt ...
最新文章
- ArrayList Iterator remove java.lang.UnsupportedOperationException
- sequelize的应用
- 光纤收发器的详细选择方法
- java 日期操作工具类_java8操作日期的工具类
- 用 Maven 做项目构建
- debian6安装后中文乱码
- 软件测试52讲-测试新技术篇
- 利用 Zabbix 监控 mysqldump 定时备份数据库是否成功 | 运维进阶
- 安装RabbitMQ无法访问(http://localhost:15672)解决方案
- 安卓开发小程序之美图秀秀
- 使用Simian进行重复代码检测
- 计算机组装工具以及装机流程,如何组装电脑,图文教程详解电脑组装全过程
- Axure 进阶教程
- 微信小程序实现箭头方向转换与日历展开功能
- JAVA:实现Blowfish区块加密算法(附完整源码)
- 鼠标计算机无法识别,如何解决usb鼠标和键盘无法识别问题
- 熬秃了头整理的网络工程师学习笔记和心得:传闻中的OSPF到底是什么
- 【路径规划】基于粒子群算法求解带时间窗的车辆路径规划问题VRPTW模型matlab源码
- 对 ArabicRSS APK 应用木马样本的分析
- 微信ios接入-Objc -all_load的坑