今天学习记录下对状态机的学习
一、状态机使用的步骤
- 可以将源码的frameworks/base/core/java/com/android/internal/util里面把StateMachine.java 、State.java 、IState.java复制到project目录中
- 自定义StateMachine类 (如 MyLife) 继承StateMachine
- 自定义状态State ( 如MyLife中不同状态-睡觉、吃饭、工作学习等状态) 继承State:重写enter、processMsg、exit
- addState加入父状态、子状态,setInitialState初始化状态
- start() 函数调用 启动状态机stateMachine
- 使用状态机,发送持有更新状态常量的Msg
- quit() 函数是关闭状态机
二、部分代码如下
//2. 自定义StateMachine类 MyLife ,该类继承 StateMachine
public class MyLife extends StateMachine {
private String TAG = "MyLife";
IdleState mIdle = new IdleState();
SleepingState mSleeping = new SleepingState();
EatingState mEating = new EatingState();
WorkingState mWorking = new WorkingState();
RestingState mResting = new RestingState();
ReadingState mReading = new ReadingState();
PoemingState mPoeming = new PoemingState();
private CompositeSubscription allSubscription = null;
private static MyLife myLife = null;
protected MyLife(String name) {
super(name);
Log.e(TAG,"new MyLife");
allSubscription = new CompositeSubscription();
//4.添加不同的状态,构成树形结构
addState(mIdle);
addState(mEating, mIdle); //可以看作 midle 为 mEating 的父状态,mEating 为 midle 的 子状态
addState(mWorking,mEating);
addState(mReading,mWorking);
addState(mPoeming,mReading);
addState(mSleeping, mIdle);
addState(mResting, mIdle);
//4.setInitialState 设置一个初始状态
setInitialState(mIdle);
}
public static MyLife getInstance(){
if(myLife == null){
myLife = new MyLife("mylife");
}
return myLife;
}
public void setContext(Context context){
this.context = context;
}
//3.定义状态机的不同状态,如闲暇时间 IdleState 继承与 State
class IdleState extends State {
//enter相当于初始化函数,类似于C++的构造函数,父状态先调用
@Override
public void enter() {
Log.e(TAG,"IdleState enter");
}
//当有消息时,当前状态的 该函数被调用
@Override
public boolean processMessage(Message message) {
Log.e(TAG,"xtk IdleState .processMessage what = " + message.what);
switch(message.what) {
case MsgState.MSG_STATE_WORKING:
Log.e(TAG,"xtk IdleState MSG_STATE_WORKING");
//6.转换状态 transitionTo
transitionTo(mEating);
//6.sendMessage发送消息
sendMessage(MsgState.MSG_STATE_EATTING);
break;
}
//注意该出这两种返回值写法,会出现不同的处理过程
//return true;
return super.processMessage(message);
}
//类似于C++的析构函数,子状态(树形结构中相对于上一级状态节点作为父状态)先调用
@Override
public void exit() {
Log.e(TAG,"xtk IdleState exit");
}
}
//3.定义状态机的不同状态,如睡觉状态 SleepingState 继承与 State
class SleepingState extends State {
......
}
//3.定义状态机的不同状态,如吃饭状态 EatingState 继承与 State
class EatingState extends State {
......
}
class WorkingState extends State {
......
}
......
private synchronized void testData(String num){
int value = Integer.valueOf(num);
Random random = new Random(10);
if(value == 8 && (random.nextInt() % 2) == 0){
Log.e(TAG,"testData MSG_STATE_GOTOWC");
transitionTo(mResting);
sendMessage(MsgState.MSG_STATE_GOTOWC);
}
if(value == 15){
Log.e(TAG,"testData MSG_STATE_SLEEPING");
transitionTo(mSleeping);
sendMessage(MsgState.MSG_STATE_SLEEPING);
}
if(value > 20){
MsgState.RUN = false;
}
}
public void startState(){
sendMessage(MsgState.MSG_STATE_WORKING);
}
}
三、启动状态机
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn = null;
private MyLife myLife = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.txtBtn);
btn.setOnClickListener(this);
myLife = MyLife.getInstance();
}
@Override
public void onClick(View v) {
Log.e("test","on Click!");
myLife.setContext(this);
myLife.start();
myLife.startState();
}
}
四、状态机学习的总结
假设如上图的树形结构状态,初始化为 S4
1.状态机列表为{ S4,S1, S0} S4在栈顶;初始化时先初始化 S0 (进入到S0的enter函数),然后S1 (进入到S0的enter函数),然后S4(进入到S0的enter函数);如果此时有消息,则依次 S4,S1,S0调用processMessage函数
2.如果转换状态,如 转换到 S5,则首先依次按照 S4,S1,S0 调用processMessage函数(如果有消息,此时消息到S0还没有被处理,则该消息将被抛弃掉),然后S4,S1 依次调用exit函数(S0未退出是因为为根节点,在S5-S2-S0这条线上),开始依次初始化 S2,S5(调用 enter函数),当前栈顶变为 S5
3.初始化(enter) S0->S1->S4; 退出(exit) S4->S1->S0;
4.中间过程:状态没有改变,同时processMessage函数返回值为 return super.processMessage(message),则每出现一条 MSG 就按照 S4->S1->S0 调用 processMessage函数
5.中间过程:状态没有改变,同时processMessage函数返回值为 return true (假设S4是这样写的),则每出现一条 MSG 就按照 S4 调用 processMessage函数,S1 S0不会被调用
6.状态没有改变和状态机没有关闭,则一直停留在该状态,等待消息
以上为个人的学习,可能会有错误的地方,如遇到,请指教
五、参考地址:
1.https://www.jianshu.com/p/f3ad78613072
2.https://blog.csdn.net/pi9nc/article/details/27503071
六、上述代码不完整
代码地址:
https://download.csdn.net/download/shiluohuashengmi/10510256