前言
在Android APP开发过程中,有时可以采用状态机来解决某些复杂业务,例如下拉刷新功能,我们可以更加行为将其划分为Normal状态、Pull状态、Loading状态,根据不同的状态我们实现该状态下行为。例如Loading状态下我们需要显示loading图标。Pull(下拉)状态下我们要计算下拉距离等等。这篇文章我们一起探讨编写一个抽象状态机,在业务模块可以继承抽象状态机来实现自己的业务状态机。
要点
1、状态切换需要在子线程中完成
Android UI跑在主线程里面,我们经常通过handler.post、view.post向主线程队列中发送消息,若当前内存占用量大或在主线程中执行了耗时任务,那么会造成主线程卡顿,所以在主线程中切换状态可能存在状态切换不及时的问题,所以我们要在子线程中完成状态切换。
具体实现采用的是HandlerThread,封装HandlerThread,提供跑在子线程中的handler,然后通过该handler.post。post的任务就跑在子线程中了。HandlerThread也是Android实现线程间通信的方法之一,用在这里再合适不过。
这里,我们提供changeState()方法,该方法可以在具体状态机中使用,也可以在持有状态机的对象中使用,目的就是切换状态
//切换状态方法 public void changeState(final State newState){ if(stoped){ Logger.d("state machine is stoped"); return; } if(mHandler == null || (autoStart && stateNow == null && newState != firstState)){ //条件检查,若if中条件不成立,则每10毫秒再调用一次本方,RunnablePocket是封装的跑在主线程的handler RunnablePocket.postDelayed(new Runnable() { @Override public void run() { changeState(newState); } },10); }else{ for(State state : allState){ if(state.stateName.equals(newState.stateName)){ //该handler是跑在子线程中的handler mHandler.post(new ChangeTask(state)); } } } }
2、逻辑方法划分
在状态切换时,我们设计如下几个逻辑方法实现状态切换
checkChange_InMachineThread(newState,stateNow):切换前做状态检查本次切换是否合乎业务逻辑,返回true代表合法继续进行状态切换
stateLeave_InMachineThread(stateNow,mainThreadHandler):该方法调用在通过检查后状态切换前,表示立即离开该状态,可以做一些收尾工作。
stateIn_InMachineThread(stateNow,mainThreadHandler):该方法调用在切换状态之后,表示当前已经切换到该状态,可以做该状态的业务逻辑了。
代码如下:
private void doChange(State newState) { //如果是初始状态且自动开始,则不做检查 if(stateNow == null && autoStart && newState == firstState){ stateNow = newState; stateIn_InMachineThread(stateNow,mainThreadHandler); return; } //检查本次状态切换是否合法 if(checkChange_InMachineThread(newState, stateNow) && newState != stateNow){ //状态切换前回调 stateLeave_InMachineThread(stateNow,mainThreadHandler); //执行状态切换 stateNow = newState; //状态切换后回调 stateIn_InMachineThread(stateNow,mainThreadHandler); return; } } }
以上回调方法在抽象状态机中为抽象方法,具体实现在业务状态机中。
完整代码就不贴了,只要掌握状态机的思想,相信各位读者自己可以写出抽象状态机。