Android 中 StateMachine 机制

分层处理消息的状态机,能够分层排列 在不同的状态下,收到不同的消息时,在不同的阶段做出不同的响应。 StateMachine 处于 Android frameworks 层源码 frameworks/base/core/java/com/android/internal/util 路径下,将此路经下的三个类 拷贝到自己的工程里,StateMachine.java,State.java,IState.java(在最后面我粘贴了这三 个代码,直接复制就可以)。

• 在 Mainactivity 里面

// 获取 状态机引用
PersonStateMachine personStateMachine = PersonStateMachine.makePerson();
// 初始状态为SleepState,发送消息MSG_WAKEUP
personStateMachine.sendMessage(PersonStateMachine.MSG_WAKEUP);

已经设置了初始状态为 SleepState,初始状态收到 MSG_WAKEUP 消息,会执行相对应的 processMessage()方法。

• 继承 StateMachine,构造函数是 protect 类型,不能实例化,要通过继承子类进行初始化 操作。

package com.xiaxl.demo;
import android.os.Message;
import android.util.Log;
import com.xiaxl.demo.statemachine.State;
import com.xiaxl.demo.statemachine.StateMachine;
public class PersonStateMachine extends StateMachine {private static final String TAG = "MachineTest";//设置状态改变标志常量public static final int MSG_WAKEUP = 1; // 醒public static final int MSG_TIRED = 2; // 困public static final int MSG_HUNGRY = 3; // 饿private static final int MSG_HALTING = 4; //停
protected PersonStateMachine(String name) {super(name);}
@Overrideprotected void onHalting() {Log.e(TAG, "PersonStateMachine halting");synchronized (this) {this.notifyAll();}}
}

• 通过 addState 方法构造状态层次结构(树形结构,创建层级),各种状态都要继承 State 类,实现自己相应的业务逻辑。(有零个或者一个父状态)

/创建状态private State mBoringState = new BoringState();// 默认状态private State mWorkState = new WorkState(); // 工作private State mEatState = new EatState(); // 吃private State mSleepState = new SleepState(); // 睡
//构造方法
protected PersonStateMachine(String name) {super(name);Log.e(TAG, "PersonStateMachine");//加入状态,初始化状态addState(mBoringState, null);addState(mSleepState, mBoringState);addState(mWorkState, mBoringState);addState(mEatState, mBoringState);}/*** 定义状态:无聊*/class BoringState extends State {@Overridepublic void enter() {Log.e(TAG, "BoringState 进入 无聊");}@Overridepublic void exit() {Log.e(TAG, "BoringState 退出 无聊");}@Overridepublic boolean processMessage(Message msg) {Log.e(TAG, "无聊 processMessage.....");return true;}}//继承State.java/*** 定义状态:工作*/class WorkState extends State {@Override//状态机进程时执行public void enter() {Log.e(TAG, "WorkState 进入 工作");}//退出时执行,释放资源@Overridepublic void exit() {Log.e(TAG, "WorkState 退出 工作");}//消息处理。@Overridepublic boolean processMessage(Message msg) {Log.e(TAG, "工作 processMessage.....");switch (msg.what) {// 收到 饿了 信号case MSG_HUNGRY:Log.e(TAG, "工作 饿");// 吃饭状态//暂时将当前消息保存到消息队列的顶端deferMessage(msg);//执行一次状态的转换transitionTo(mEatState);// 发送信号sendMessage(obtainMessage(MSG_TIRED));break;default:return false;}return true;}
/*** 定义状态:睡觉*/class SleepState extends State {@Overridepublic void enter() {Log.e(TAG, "SleepState 进入 睡觉");}@Overridepublic void exit() {Log.e(TAG, "SleepState 退出 睡觉");}@Overridepublic boolean processMessage(Message msg) {Log.e(TAG, "睡觉 processMessage.....");switch (msg.what) {// 收到清醒信号case MSG_WAKEUP:Log.e(TAG, "睡觉 醒");// 进入工作状态deferMessage(msg);transitionTo(mWorkState);////发送饿了信号...sendMessage(obtainMessage(MSG_HUNGRY));break;case MSG_HALTING:Log.e(TAG, "睡觉 停");// 停止transitionToHaltingState();//过渡到停止状态break;default:return false;}return true;}}
}

• 通过 setInitialDtate 设置初始状态

 // sleep状态为初始状态setInitialState(mSleepState);

• 调用 start 方法启动状态机。

 public static PersonStateMachine makePerson() {Log.e(TAG, "PersonStateMachine makePerson");PersonStateMachine person = new PersonStateMachine("Person");person.start();return person;}

• 开始从初始状态最顶层的父状态开始逐层调用 enter 方法,在所有的 message 执行前被调 用。例如:无聊 -> 睡觉,先执行无聊的 enter,再执行睡觉的 enter,最后 message 会被 送到当前的状态执行

此时:无聊(父状态)------> 睡觉

• 当状态机收到 message(MainActivity.java 传来的 MSG_WAKEUP)之后,当前状态的 processMessage()会被调用,也就是睡觉的 processMessage()会被调用(因为 switch-case 匹配上了),然后通过 transitionTo()跳转到新的状态(就要先退出,才能再转换成新 的状态)。

注意:

状态的转换会导致当前状态的退出,和新状态的进入,当从当前状态退出时,会逐 层向上调用父状态的退出 exit 函数,但注意,这种逐层调用,会在当前状态和目标 状态的共同父状态处不再执行 exit(),如果前状态和目标状态的不存在共同的父状 态,则彻底退出当前状态的所有父状态,并进入新状态。

此时:睡觉 -----> 工作

在这里注意一下: deferMessage(msg); 因为有了这个东西,将当前的消息(也就是传过来的 MSG_WAKEUP)保存到消息 队列的顶端,当进入工作的状态之后,swich-case 的就是消息队列顶端的 message,但是匹配不上,那么就会 default,返回 false。 【deferMessage 方法会将该消息保存在一个延迟队列中,这时并不发送出去,而 是会在下一次状态转变的时候(例如从 A 状态变为 B 状态),将延迟队列中的所有 消息放在消息队列的最前面。这些消息就会在 B 状态作为当前状态时被处理。 】

• 如果当前状态执行完 processMessage()方法返回了 false,也就是对当前消息 NOT_HANDLED(不处理当前消息), 那么就会向上调用这个状态的父状态执行方法。 (在 addState 的时候,工作的父状态是无聊)(一般终有一个状态能够处理消息(返回 true),如果最顶端的父类都没有处理,会被记录到 unhandledMessage()里面做最后的 处理,一般是丢掉,也可以自己定义最后的处理函数)

当返回了 true 之后,就是可以处理 message 了,然后根据睡觉状态发送过来的 message 进行 switch-case,可以匹配之后,就能继续往下进行了。

• 当所有进程结束之后,最后,发送一个结束的信号,调用 transitionToHaltingState()方 法,StateMachine 会跳转到内部的 HaltingState 和调用 halting,如果 StateMachine 正 常的退出,可以调用 quit 或者 abort,调用 quit 会退出当前状态和他的父状态,调用 onQuiting 之后退出 Thread 和 Loopers。

 // 发出结束信号...sendMessage(obtainMessage(MSG_HALTING));
 case MSG_HALTING:Log.e(TAG, "睡觉 停");// 停止transitionToHaltingState();//过渡到停止状态break;

start()方法用于启动状态机,transitionTo()方法用于设置新状态, performTransitions()是去切换新状态,sendMessage()方法用于向 mSmHandler 发送消息,mSmHandler 的 handleMessage 方法会把消息抛个当 前状态的 proccessMessage()方法处理。

有不对的地方请指正

Android状态机的简单理解相关推荐

  1. Android:LayoutParams简单理解和说明

    LayoutParams 1.LayoutParams 1.1 定义 1.2 使用说明 1.3 LinearLayout.LayoutParams使用 参考 1.LayoutParams 写的非常好 ...

  2. Android回调的简单理解

    1.什么是回调 回调的定义是在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类, ...

  3. android中适配器的作用,适配器模式 在Android中的简单理解

    Android 在Android上提到适配器模式就会想到最常用的ListView和BaseAdapter 在这个功能的使用中,类似于适配器模式的对象适配器 例如在ListView中想用一个getVie ...

  4. Android:RecyclerView简单理解和基本使用

    RecyclerView RecyclerView 一.RecyclerView 二.RecyclerView基本介绍: 三.RecyclerView基本实现: 参考 RecyclerView 一.R ...

  5. Android:安卓学习笔记之navigation的简单理解和使用

    Android navigation的简单理解和使用 1 .基本概念 1.1.背景 1.2.含义 2.组成 2.1.Navigation graph 2.2.NavHostFragment 2.3.N ...

  6. Android:安卓学习笔记之Bitmap的简单理解和使用

    Android Bitmap的简单理解和使用 Android Bitmap 一.Bitmap的定义 二.Bitmap的格式 2.1 存储格式 2.2 压缩格式 三.Bitmap创建方法 3.1 Bit ...

  7. android 点击事件消费,Android View事件分发和消费源码简单理解

    Android View事件分发和消费源码简单理解 前言: 开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白.中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开 ...

  8. Android:安卓学习笔记之共享元素的简单理解和使用

    Android 共享元素的简单理解和使用 1 .基本概念 2.基本使用 1.Activity to Activity跳转实现 1.1.使用步骤 1.2.案例说明 2.Fragment to Fragm ...

  9. Android:安卓学习笔记之OkHttp原理的简单理解和使用

    Android OkHttp使用原理的简单理解和使用 OkHttp 0.前言 1.请求与响应流程 1.1 请求的封装 1.2 请求的发送 1.3 请求的调度 1.4 请求的处理 2.拦截器 2.1 R ...

最新文章

  1. Java_Web使用简单的批处理操作
  2. redis安装 linux步骤,【linux安装redis完整步骤】
  3. 计算理论2--可计算理论
  4. LeetCode Algorithm 589. N 叉树的前序遍历
  5. gevent-tutorial翻译和解读
  6. 【C++grammar】文件系统以及path类使用
  7. Java微服务篇3——Lucene
  8. 数据库即时搜索_加速数据库恢复; 即时回滚和数据库恢复
  9. 排序总结---常用的排序算法总结,java和js实现
  10. [oracle] 设置PL/SQL Developer 字符集
  11. SpringBoot整合mybatis 配置文件备份
  12. 前端实现打印页面的指定内容 + 快递面单的模板
  13. PAT简介和2019年秋季浙大PAT考试报名流程
  14. CRM系统创建营销活动
  15. Android 图片裁剪
  16. 总结--linux常用配置文件总结
  17. UISlider实现背景图
  18. Android 系统内的守护进程 - core类中的服务 (5) : logd
  19. 睿智的法杖v8.28ti
  20. 基于JavaWeb的个人空间个人网站个人博客系统设计与实现

热门文章

  1. 拓幻图形学工程师教学手册(第一讲)|一字一字敲出OpenGL学习教程
  2. 为Canon PIXMA iP1000喷墨打印机安装驱动程序
  3. 思科交换机65系列配置
  4. C++如何定义一个长度超过一百万的数组
  5. 工业继电器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  6. 哈理工计算机学院学生会技术部,某大学学生会网络技术部规章制度(网友投稿)...
  7. [实用资料系列]注册表技术大全「五注册表优化全攻略」
  8. 使用R语言包clusterProfiler做KEGG富集分析时出现的错误及解决方法
  9. 贪心算法之活动安排问题(填表详解+思路解析)
  10. 让我们泪流满面的电影经典台词