Android状态机的简单理解

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);
 }
@Override
 protected 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 {
 @Override
 public void enter() {
 Log.e(TAG, "BoringState 进入 无聊");
 }
 @Override
 public void exit() {
 Log.e(TAG, "BoringState 退出 无聊");
 }
 @Override
 public boolean processMessage(Message msg) {
 Log.e(TAG, "无聊 processMessage.....");
 return true;
 }
 }
 //继承State.java
 /**
 * 定义状态:工作
 */
 class WorkState extends State {
 @Override
 //状态机进程时执行
 public void enter() {
 Log.e(TAG, "WorkState 进入 工作");
 }
 //退出时执行,释放资源
 @Override
 public void exit() {
 Log.e(TAG, "WorkState 退出 工作");
 }
 //消息处理。
 @Override
 public 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 {
 @Override
 public void enter() {
 Log.e(TAG, "SleepState 进入 睡觉");
 }
 @Override
 public void exit() {
 Log.e(TAG, "SleepState 退出 睡觉");
 }
 @Override
 public 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()方法处理。

有不对的地方请指正

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张子怡です

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值