消息注册机制是MessageHandler的一个应用,它的好处就是能在程序中自如地控制消息注册和消息发送两个步骤。
但是很多情况下,问题的解决是在很多个环节完成的,每个环节理解成特定的状态,在每个状态下都会有新消息的发送或者新状态的切换。那么设计就需要考虑如何将Message的处理操作放到指定的状态机中,这是程序设计的关键。
总体思想:
(1)先初始化状态机,设置初始状态。
(2)内存中加载handler对象,要知道所有Message的处理都的经过它,所以在复写handleMessage的时候需要将当前Message分发到当前最新状态。
下面是模拟程序,刚写的,没调试,而且不全面,只写了骨架,但更直观便于阅读。明天调试看看,得出完整版本的,最好结合PDP建立过程讲解PDP建立的状态机过程。
这里列举3个类:
package com.zte.liu.statemachine;
public class HierarchicalState {
public void enter(){
}
public void exit(){
}
public void processMessage(){
}
}
package com.zte.liu.statemachine;
import com.zte.liu.messagehandler.HandlerThread;
import com.zte.liu.messagehandler.Looper;
import com.zte.liu.messagehandler.Message;
public class HierarchicalStateMachine {
private HsmHandler mHandler;
private HandlerThread mHandlerThread;
private DefaultState defaultState = new DefaultState();
private InactiveState inActiveState = new InactiveState();
private ActivingState activingState = new ActivingState();
private ActiveState activeState = new ActiveState();
private HaltingState haltingState = new HaltingState();
private QuitingState quitingState = new QuitingState();
public HierarchicalStateMachine(){
mHandlerThread = new HandlerThread();
mHandlerThread.start();
Looper looper = mHandlerThread.getLooper();
mHandler = new HsmHandler(looper);
}
private class DefaultState extends HierarchicalState{
}
private class InactiveState extends HierarchicalState{
}
private class ActivingState extends HierarchicalState{
}
private class ActiveState extends HierarchicalState{
}
private class HaltingState extends HierarchicalState{
}
private class QuitingState extends HierarchicalState{
}
public void addState(HierarchicalState state){
mHandler.addState(state, null);
}
public void addState(HierarchicalState state, HierarchicalState parent){
mHandler.addState(state, parent);
}
public void setInitialState(HierarchicalState state){
mHandler.setInitialState(state);
}
public void start(){
mHandler.completeConstruction();
}
public Message obtainMessage(int what, Object obj){
return mHandler.obtainMessage(what, obj);
}
public void sendMessage(Message msg){
if(msg != null){
msg.sendToTarget();
}
}
public void deferMessage(Message msg){
mHandler.deferMessage(msg);
}
public void transitionTo(HierarchicalState destState){
mHandler.transitionTo(destState);
}
}
package com.zte.liu.statemachine;
import java.util.ArrayList;
import java.util.HashMap;
import com.zte.liu.messagehandler.Handler;
import com.zte.liu.messagehandler.Looper;
import com.zte.liu.messagehandler.Message;
import com.zte.liu.messagehandler.MessageQueue;
public class HsmHandler extends Handler {
private HashMap<HierarchicalState, StateInfo> mStateInfo = new HashMap<HierarchicalState, StateInfo>();
private HierarchicalState mInitialState = null;
private HierarchicalState mDestState = null;
private ArrayList<StateInfo> mInitialStateList = new ArrayList<StateInfo>();
private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
public HsmHandler(Looper looper) {
super(looper);
}
private class StateInfo{
HierarchicalState state;
HierarchicalState parentState;
boolean active;
}
public void addState(HierarchicalState state, HierarchicalState parentState){//只在非多线程情况
if(state == null){
throw new RuntimeException("state cannot be null when adding state.");
}
/* if(mStateInfo.containsKey(state) && mStateInfo.get(state).parentState!=parentState){
throw new RuntimeException("we cannot add a state with different parents.");
}
*/
if(mStateInfo.containsKey(state)){
return;
}
StateInfo stateInfo = new StateInfo();
stateInfo.state = state;
stateInfo.parentState = parentState;
stateInfo.active = false;
mStateInfo.put(state, stateInfo);
}
public void setInitialState(HierarchicalState state){
if(!mStateInfo.containsKey(state)){
throw new RuntimeException("cannot set a initial state which is not contained in the build tree.");
}
mInitialState = state;
}
public void completeConstruction(){
if(mInitialState == null){
return;
}
StateInfo initialStateInfo = mStateInfo.get(mInitialState);
while(initialStateInfo != null){
mInitialStateList.add(initialStateInfo);
if(initialStateInfo.parentState == null){
initialStateInfo = null;
}else{
initialStateInfo = mStateInfo.get(initialStateInfo.parentState);
}
}
invokeEnterMethods(null);
performTransitions();
}
public void invokeEnterMethods(StateInfo commonStateInfo){
int start = mInitialStateList.size() - 1;
for(int i=mInitialStateList.size()-1; i>=0; i--){
if(mInitialStateList.get(i) == commonStateInfo){
start = i - 1;
break;
}
}
for(int i=start; i>=0; i--){
StateInfo stateInfo = mInitialStateList.get(i);
stateInfo.state.enter();
stateInfo.active = true;
}
}
public void invokeExitMethods(StateInfo commonStateInfo){
for(int i=0; i<mInitialStateList.size()-1; i++){
StateInfo stateInfo = (StateInfo)mInitialStateList.get(i);
if(stateInfo != commonStateInfo){
stateInfo.state.exit();
stateInfo.active = false;
}else{
break;
}
}
}
public void performTransitions(){
if(mDestState == null){
return;
}
ArrayList<StateInfo> tempList = new ArrayList<StateInfo>();
StateInfo commonStateInfo = getCommonStateInfo(mDestState, tempList);
invokeExitMethods(commonStateInfo);
refreshInitialStateList(commonStateInfo, tempList);
invokeEnterMethods(commonStateInfo);
moveDeferredMsgAtFrontQueue();
}
public void deferMessage(Message msg){
mDeferredMessages.add(msg);
}
public void handleMessage(Message msg){//重写!!
///
//
}
public void transitionTo(HierarchicalState destState){
mDestState = destState;
}
private StateInfo getCommonStateInfo(HierarchicalState destState, ArrayList<StateInfo> tempList){
StateInfo stateInfo = mStateInfo.get(destState);
while(stateInfo!=null && stateInfo.active==false){
tempList.add(stateInfo);
if(stateInfo.parentState == null){
stateInfo = null;
}else{
stateInfo = mStateInfo.get(stateInfo.parentState);
}
}
return stateInfo;
}
private void refreshInitialStateList(StateInfo commonStateInfo, ArrayList<StateInfo> tempList){
for(int i=0; i<mInitialStateList.size()-1; i++){
if(mInitialStateList.get(i) != commonStateInfo){
mInitialStateList.remove(i);
}
}
for(int i=tempList.size()-1; i>=0; i--){
mInitialStateList.add(0, tempList.get(i));
}
}
private void moveDeferredMsgAtFrontQueue(){
MessageQueue msgQueue = this.getLooper().getQueue();
for(int i=mDeferredMessages.size()-1; i>=0; i--){
msgQueue.addToFront(mDeferredMessages.get(i));
}
}
}