Android系统自带的层次状态机StateMachine(Hierarchical State Machine)

mStateMachine = (HumanStateMachine) sm;

}

@Override

public void enter() {

System.out.println(getName() + “enter”);

}

@Override

public void exit() {

System.out.println(getName() + “exit”);

}

@Override

public String getName() {

return “工作”;

}

@Override

public boolean processMessage(Message msg) {

System.out.println(“WorkState:” + msg.what);

boolean ret;

switch (msg.what) {

case StateDef.CMD_WORK:

System.out.println(“WorkState:工作…”);

ret = StateMachine.HANDLED;

break;

default:

ret = StateMachine.NOT_HANDLED;

break;

}

return ret;

}

}

import android.os.Message;

//吃饭状态。

public class EatState extends State {

private HumanStateMachine mStateMachine;

public EatState(StateMachine sm) {

this.mStateMachine = (HumanStateMachine) sm;

}

@Override

public void enter() {

System.out.println(getName() + “enter”);

}

@Override

public void exit() {

System.out.println(getName() + “exit”);

}

@Override

public boolean processMessage(Message msg) {

System.out.println(“EatState:” + msg.what);

boolean ret;

switch (msg.what) {

case StateDef.CMD_EAT:

System.out.println(“EatState:吃…”);

ret = StateMachine.HANDLED;

break;

default:

ret = StateMachine.NOT_HANDLED;

break;

}

return ret;

}

@Override

public String getName() {

return “吃”;

}

}

import android.os.Message;

//下班状态。

public class OffworkState extends State {

private HumanStateMachine mStateMachine;

public OffworkState(StateMachine sm) {

mStateMachine = (HumanStateMachine) sm;

}

@Override

public void enter() {

System.out.println(getName() + “enter”);

;

}

@Override

public void exit() {

System.out.println(getName() + “exit”);

}

@Override

public boolean processMessage(Message msg) {

System.out.println(“OffworkState:” + msg.what);

boolean ret;

switch (msg.what) {

case StateDef.CMD_OFFWORK:

System.out.println(“OffworkState…”);

ret = StateMachine.HANDLED;

break;

default:

ret = StateMachine.NOT_HANDLED;

break;

}

return ret;

}

@Override

public String getName() {

return “下班”;

}

}

import android.os.Message;

//睡觉状态。

public class SleepState extends State {

private HumanStateMachine mStateMachine;

public SleepState(StateMachine sm) {

this.mStateMachine = (HumanStateMachine) sm;

}

@Override

public void enter() {

System.out.println(getName() + “enter”);

}

@Override

public void exit() {

System.out.println(getName() + “exit”);

}

@Override

public String getName() {

return “睡觉”;

}

@Override

public boolean processMessage(Message msg) {

System.out.println(“SleepState:” + msg.what);

boolean ret;

switch (msg.what) {

case StateDef.CMD_SLEEP:

System.out.println(“SleepState:睡觉…”);

ret = StateMachine.HANDLED;

break;

default:

ret = StateMachine.NOT_HANDLED;

break;

}

return ret;

}

}

测试:

private void test() {

HumanStateMachine sm = new HumanStateMachine(“人”);

sm.sendMessage(sm.obtainMessage(StateDef.CMD_TIRED));

sm.sendMessage(sm.obtainMessage(StateDef.CMD_HUNGRY));

sm.quit();

}

输出:

I/System.out: 缺省enter

I/System.out: 睡觉enter

I/System.out: SleepState:4

I/System.out: DefaultState:4

I/System.out: DefaultState->切换睡觉状态

I/System.out: 睡觉exit

I/System.out: 睡觉enter

I/System.out: SleepState:8

I/System.out: SleepState:睡觉…

I/System.out: SleepState:2

I/System.out: DefaultState:2

I/System.out: DefaultState->切换吃饭状态

I/System.out: 睡觉exit

I/System.out: 起床enter

I/System.out: 吃enter

I/System.out: EatState:5

I/System.out: EatState:吃…

I/System.out: 吃exit

I/System.out: 起床exit

I/System.out: 缺省exit

附:

经典状态机模式:

https://blog.csdn.net/zhangphil/article/details/88741024

https://blog.csdn.net/zhangphil/article/details/91060040

https://blog.csdn.net/zhangphil/article/details/90042388


Android平台自带的层次状态机实现的源代码


import android.os.Message;

/**

  • {@hide}

  • The interface for implementing states in a {@link StateMachine}

*/

public interface IState {

/**

  • Returned by processMessage to indicate the the message was processed.

*/

static final boolean HANDLED = true;

/**

  • Returned by processMessage to indicate the the message was NOT processed.

*/

static final boolean NOT_HANDLED = false;

/**

  • Called when a state is entered.

*/

void enter();

/**

  • Called when a state is exited.

*/

void exit();

/**

  • Called when a message is to be processed by the

  • state machine.

  • This routine is never reentered thus no synchronization

  • is needed as only one processMessage method will ever be

  • executing within a state machine at any given time. This

  • does mean that processing by this routine must be completed

  • as expeditiously as possible as no subsequent messages will

  • be processed until this routine returns.

  • @param msg to process

  • @return HANDLED if processing has completed and NOT_HANDLED

  •     if the message wasn't processed.
    

*/

boolean processMessage(Message msg);

/**

  • Name of State for debugging purposes.

  • @return name of state.

*/

String getName();

}

import android.os.Message;

/**

  • {@hide}

  • The class for implementing states in a StateMachine

*/

public class State implements IState {

/**

  • Constructor

*/

protected State() {

}

/* (non-Javadoc)

  • @see com.android.internal.util.IState#enter()

*/

@Override

public void enter() {

}

/* (non-Javadoc)

  • @see com.android.internal.util.IState#exit()

*/

@Override

public void exit() {

}

/* (non-Javadoc)

  • @see com.android.internal.util.IState#processMessage(android.os.Message)

*/

@Override

public boolean processMessage(Message msg) {

return false;

}

/**

  • Name of State for debugging purposes.

  • This default implementation returns the class name, returning

  • the instance name would better in cases where a State class

  • is used for multiple states. But normally there is one class per

  • state and the class name is sufficient and easy to get. You may

  • want to provide a setName or some other mechanism for setting

  • another name if the class name is not appropriate.

  • @see com.android.internal.util.IState#processMessage(android.os.Message)

*/

@Override

public String getName() {

String name = getClass().getName();

int lastDollar = name.lastIndexOf(‘$’);

return name.substring(lastDollar + 1);

}

}

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Looper;

import android.os.Message;

import android.text.TextUtils;

import android.util.Log;

import java.io.FileDescriptor;

import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.Calendar;

import java.util.HashMap;

import java.util.Vector;

/**

  • {@hide}

  • The state machine defined here is a hierarchical state machine which processes messages

  • and can have states arranged hierarchically.

  • A state is a State object and must implement

  • processMessage and optionally enter/exit/getName.

  • The enter/exit methods are equivalent to the construction and destruction

  • in Object Oriented programming and are used to perform initialization and

  • cleanup of the state respectively. The getName method returns the

  • name of the state the default implementation returns the class name it may be

  • desirable to have this return the name of the state instance name instead.

  • In particular if a particular state class has multiple instances.

  • When a state machine is created addState is used to build the

  • hierarchy and setInitialState is used to identify which of these

  • is the initial state. After construction the programmer calls start

  • which initializes and starts the state machine. The first action the StateMachine

  • is to the invoke enter for all of the initial state’s hierarchy,

  • starting at its eldest parent. The calls to enter will be done in the context

  • of the StateMachines Handler not in the context of the call to start and they

  • will be invoked before any messages are processed. For example, given the simple

  • state machine below mP1.enter will be invoked and then mS1.enter. Finally,

  • messages sent to the state machine will be processed by the current state,

  • in our simple state machine below that would initially be mS1.processMessage.

mP1

/ \

mS2 mS1 ----> initial state

  • After the state machine is created and started, messages are sent to a state

  • machine using sendMessage and the messages are created using

  • obtainMessage. When the state machine receives a message the

  • current state’s processMessage is invoked. In the above example

  • mS1.processMessage will be invoked first. The state may use transitionTo

  • to change the current state to a new state

  • Each state in the state machine may have a zero or one parent states and if

  • a child state is unable to handle a message it may have the message processed

  • by its parent by returning false or NOT_HANDLED. If a message is never processed

  • unhandledMessage will be invoked to give one last chance for the state machine

  • to process the message.

  • When all processing is completed a state machine may choose to call

  • transitionToHaltingState. When the current processingMessage

  • returns the state machine will transfer to an internal HaltingState

  • and invoke halting. Any message subsequently received by the state

  • machine will cause haltedProcessMessage to be invoked.

  • If it is desirable to completely stop the state machine call quit or

  • abort. These will call exit of the current state and its parents, call

  • onQuiting and then exit Thread/Loopers.

  • In addition to processMessage each State has

  • an enter method and exit method which may be overridden.

  • Since the states are arranged in a hierarchy transitioning to a new state

  • causes current states to be exited and new states to be entered. To determine

  • the list of states to be entered/exited the common parent closest to

  • the current state is found. We then exit from the current state and its

  • parent’s up to but not including the common parent state and then enter all

  • of the new states below the common parent down to the destination state.

  • If there is no common parent all states are exited and then the new states

  • are entered.

  • Two other methods that states can use are deferMessage and

  • sendMessageAtFrontOfQueue. The sendMessageAtFrontOfQueue sends

  • a message but places it on the front of the queue rather than the back. The

  • deferMessage causes the message to be saved on a list until a

  • transition is made to a new state. At which time all of the deferred messages

  • will be put on the front of the state machine queue with the oldest message

  • at the front. These will then be processed by the new current state before

  • any other messages that are on the queue or might be added later. Both of

  • these are protected and may only be invoked from within a state machine.

  • To illustrate some of these properties we'll use state machine with an 8

  • state hierarchy:

mP0

/ \

mP1 mS0

/ \

mS2 mS1

/ \ \

mS3 mS4 mS5 —> initial state

  • After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.

  • So the order of calling processMessage when a message is received is mS5,

  • mS1, mP1, mP0 assuming each processMessage indicates it can’t handle this

  • message by returning false or NOT_HANDLED.

  • Now assume mS5.processMessage receives a message it can handle, and during

  • the handling determines the machine should change states. It could call

  • transitionTo(mS4) and return true or HANDLED. Immediately after returning from

  • processMessage the state machine runtime will find the common parent,

  • which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then

  • mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So

  • when the next message is received mS4.processMessage will be invoked.

  • Now for some concrete examples, here is the canonical HelloWorld as a state machine.

  • It responds with “Hello World” being printed to the log for every message.

class HelloWorld extends StateMachine {

HelloWorld(String name) {

super(name);

addState(mState1);

setInitialState(mState1);

}

public static HelloWorld makeHelloWorld() {

HelloWorld hw = new HelloWorld(“hw”);

hw.start();

return hw;

}

class State1 extends State {

@Override public boolean processMessage(Message message) {

Log.d(TAG, “Hello World”);

return HANDLED;

}

}

State1 mState1 = new State1();

}

void testHelloWorld() {

HelloWorld hw = makeHelloWorld();

hw.sendMessage(hw.obtainMessage());

}

  • A more interesting state machine is one with four states

  • with two independent parent states.

mP1 mP2

/ \

mS2 mS1

  • Here is a description of this state machine using pseudo code.

state mP1 {

enter { log(“mP1.enter”); }

exit { log(“mP1.exit”); }

on msg {

CMD_2 {

send(CMD_3);

defer(msg);

transitonTo(mS2);

return HANDLED;

}

return NOT_HANDLED;

}

}

INITIAL

state mS1 parent mP1 {

enter { log(“mS1.enter”); }

exit { log(“mS1.exit”); }

on msg {

CMD_1 {

transitionTo(mS1);

return HANDLED;

}

return NOT_HANDLED;

}

}

state mS2 parent mP1 {

enter { log(“mS2.enter”); }

exit { log(“mS2.exit”); }

on msg {

CMD_2 {

send(CMD_4);

return HANDLED;

}

CMD_3 {

defer(msg);

transitionTo(mP2);

return HANDLED;

}

return NOT_HANDLED;

}

}

state mP2 {

enter {

log(“mP2.enter”);

send(CMD_5);

}

exit { log(“mP2.exit”); }

on msg {

CMD_3, CMD_4 { return HANDLED; }

CMD_5 {

transitionTo(HaltingState);

return HANDLED;

}

return NOT_HANDLED;

}

}

  • The implementation is below and also in StateMachineTest:

class Hsm1 extends StateMachine {

private static final String TAG = “hsm1”;

public static final int CMD_1 = 1;

public static final int CMD_2 = 2;

public static final int CMD_3 = 3;

public static final int CMD_4 = 4;

public static final int CMD_5 = 5;

public static Hsm1 makeHsm1() {

Log.d(TAG, “makeHsm1 E”);

Hsm1 sm = new Hsm1(“hsm1”);

sm.start();

Log.d(TAG, “makeHsm1 X”);

return sm;

}

Hsm1(String name) {

super(name);

Log.d(TAG, “ctor E”);

// Add states, use indentation to show hierarchy

addState(mP1);

addState(mS1, mP1);

addState(mS2, mP1);

addState(mP2);

// Set the initial state

setInitialState(mS1);

Log.d(TAG, “ctor X”);

}

class P1 extends State {

@Override public void enter() {

Log.d(TAG, “mP1.enter”);

}

@Override public boolean processMessage(Message message) {

boolean retVal;

Log.d(TAG, “mP1.processMessage what=” + message.what);

switch(message.what) {

case CMD_2:

// CMD_2 will arrive in mS2 before CMD_3

sendMessage(obtainMessage(CMD_3));

deferMessage(message);

transitionTo(mS2);

retVal = HANDLED;

break;

default:

// Any message we don’t understand in this state invokes unhandledMessage

retVal = NOT_HANDLED;

break;

}

return retVal;

}

@Override public void exit() {

Log.d(TAG, “mP1.exit”);

}

}

class S1 extends State {

@Override public void enter() {

Log.d(TAG, “mS1.enter”);

}

@Override public boolean processMessage(Message message) {

Log.d(TAG, “S1.processMessage what=” + message.what);

if (message.what == CMD_1) {

// Transition to ourself to show that enter/exit is called

transitionTo(mS1);

return HANDLED;

} else {

// Let parent process all other messages

return NOT_HANDLED;

}

}

@Override public void exit() {

Log.d(TAG, “mS1.exit”);

}

}

class S2 extends State {

@Override public void enter() {

Log.d(TAG, “mS2.enter”);

}

@Override public boolean processMessage(Message message) {

boolean retVal;

Log.d(TAG, “mS2.processMessage what=” + message.what);

switch(message.what) {

case(CMD_2):

sendMessage(obtainMessage(CMD_4));

retVal = HANDLED;

break;

case(CMD_3):

deferMessage(message);

transitionTo(mP2);

retVal = HANDLED;

break;

default:

retVal = NOT_HANDLED;

break;

}

return retVal;

}

@Override public void exit() {

Log.d(TAG, “mS2.exit”);

}

}

class P2 extends State {

@Override public void enter() {

Log.d(TAG, “mP2.enter”);

sendMessage(obtainMessage(CMD_5));

}

@Override public boolean processMessage(Message message) {

Log.d(TAG, “P2.processMessage what=” + message.what);

switch(message.what) {

case(CMD_3):

break;

case(CMD_4):

break;

case(CMD_5):

transitionToHaltingState();

break;

}

return HANDLED;

}

@Override public void exit() {

Log.d(TAG, “mP2.exit”);

}

}

@Override

void onHalting() {

Log.d(TAG, “halting”);

synchronized (this) {

this.notifyAll();

}

}

P1 mP1 = new P1();

S1 mS1 = new S1();

S2 mS2 = new S2();

P2 mP2 = new P2();

}

  • If this is executed by sending two messages CMD_1 and CMD_2

  • (Note the synchronize is only needed because we use hsm.wait())

Hsm1 hsm = makeHsm1();

synchronize(hsm) {

hsm.sendMessage(obtainMessage(hsm.CMD_1));

hsm.sendMessage(obtainMessage(hsm.CMD_2));

try {

// wait for the messages to be handled

hsm.wait();

} catch (InterruptedException e) {

Log.e(TAG, "exception while waiting " + e.getMessage());

}

}

  • The output is:

D/hsm1 ( 1999): makeHsm1 E

D/hsm1 ( 1999): ctor E

D/hsm1 ( 1999): ctor X

D/hsm1 ( 1999): mP1.enter

D/hsm1 ( 1999): mS1.enter

D/hsm1 ( 1999): makeHsm1 X

D/hsm1 ( 1999): mS1.processMessage what=1

D/hsm1 ( 1999): mS1.exit

D/hsm1 ( 1999): mS1.enter

D/hsm1 ( 1999): mS1.processMessage what=2

D/hsm1 ( 1999): mP1.processMessage what=2

D/hsm1 ( 1999): mS1.exit

D/hsm1 ( 1999): mS2.enter

D/hsm1 ( 1999): mS2.processMessage what=2

D/hsm1 ( 1999): mS2.processMessage what=3

D/hsm1 ( 1999): mS2.exit

D/hsm1 ( 1999): mP1.exit

D/hsm1 ( 1999): mP2.enter

D/hsm1 ( 1999): mP2.processMessage what=3

D/hsm1 ( 1999): mP2.processMessage what=4

D/hsm1 ( 1999): mP2.processMessage what=5

D/hsm1 ( 1999): mP2.exit

D/hsm1 ( 1999): halting

*/

public class StateMachine {

private static final String TAG = “StateMachine”;

private String mName;

/** Message.what value when quitting */

private static final int SM_QUIT_CMD = -1;

/** Message.what value when initializing */

private static final int SM_INIT_CMD = -2;

/**

  • Convenience constant that maybe returned by processMessage

  • to indicate the the message was processed and is not to be

  • processed by parent states

*/

public static final boolean HANDLED = true;

/**

  • Convenience constant that maybe returned by processMessage

  • to indicate the the message was NOT processed and is to be

  • processed by parent states

*/

public static final boolean NOT_HANDLED = false;

/**

  • StateMachine logging record.

  • {@hide}

*/

public static class LogRec {

private long mTime;

private int mWhat;

private String mInfo;

private State mState;

private State mOrgState;

/**

  • Constructor

  • @param msg

  • @param state that handled the message

  • @param orgState is the first state the received the message but

  • did not processes the message.

*/

LogRec(Message msg, String info, State state, State orgState) {

update(msg, info, state, orgState);

}

/**

  • Update the information in the record.

  • @param state that handled the message

  • @param orgState is the first state the received the message but

  • did not processes the message.

*/

public void update(Message msg, String info, State state, State orgState) {

mTime = System.currentTimeMillis();

mWhat = (msg != null) ? msg.what : 0;

mInfo = info;

mState = state;

mOrgState = orgState;

}

/**

  • @return time stamp

*/

public long getTime() {

return mTime;

}

/**

  • @return msg.what

*/

public long getWhat() {

return mWhat;

}

/**

  • @return the command that was executing

*/

public String getInfo() {

return mInfo;

}

/**

  • @return the state that handled this message

*/

public State getState() {

return mState;

}

/**

  • @return the original state that received the message.

*/

public State getOriginalState() {

return mOrgState;

}

/**

  • @return as string

*/

public String toString(StateMachine sm) {

StringBuilder sb = new StringBuilder();

sb.append(“time=”);

Calendar c = Calendar.getInstance();

c.setTimeInMillis(mTime);

sb.append(String.format(“%tm-%td %tH:%tM:%tS.%tL”, c, c, c, c, c, c));

sb.append(" state=");

sb.append(mState == null ? “” : mState.getName());

sb.append(" orgState=");

sb.append(mOrgState == null ? “” : mOrgState.getName());

sb.append(" what=");

String what = sm.getWhatToString(mWhat);

if (TextUtils.isEmpty(what)) {

sb.append(mWhat);

sb.append(“(0x”);

sb.append(Integer.toHexString(mWhat));

sb.append(“)”);

} else {

sb.append(what);

}

if ( ! TextUtils.isEmpty(mInfo)) {

sb.append(" ");

sb.append(mInfo);

}

return sb.toString();

}

}

/**

  • A list of log records including messages recently processed by the state machine.

  • The class maintains a list of log records including messages

  • recently processed. The list is finite and may be set in the

  • constructor or by calling setSize. The public interface also

  • includes size which returns the number of recent records,

  • count which is the number of records processed since the

  • the last setSize, get which returns a record and

  • add which adds a record.

*/

private static class LogRecords {

private static final int DEFAULT_SIZE = 20;

private Vector mLogRecords = new Vector();

private int mMaxSize = DEFAULT_SIZE;

private int mOldestIndex = 0;

private int mCount = 0;

/**

  • private constructor use add

*/

private LogRecords() {

}

/**

  • Set size of messages to maintain and clears all current records.

  • @param maxSize number of records to maintain at anyone time.

*/

synchronized void setSize(int maxSize) {

mMaxSize = maxSize;

mCount = 0;

mLogRecords.clear();

}

/**

  • @return the number of recent records.

*/

synchronized int size() {

return mLogRecords.size();

}

/**

  • @return the total number of records processed since size was set.

*/

synchronized int count() {

return mCount;

}

/**

  • Clear the list of records.

*/

synchronized void cleanup() {

mLogRecords.clear();

}

/**

  • @return the information on a particular record. 0 is the oldest

  • record and size()-1 is the newest record. If the index is to

  • large null is returned.

*/

synchronized LogRec get(int index) {

int nextIndex = mOldestIndex + index;

if (nextIndex >= mMaxSize) {

nextIndex -= mMaxSize;

}

if (nextIndex >= size()) {

return null;

} else {

return mLogRecords.get(nextIndex);

}

}

/**

  • Add a processed message.

  • @param msg

  • @param messageInfo to be stored

  • @param state that handled the message

  • @param orgState is the first state the received the message but

  • did not processes the message.

*/

synchronized void add(Message msg, String messageInfo, State state, State orgState) {

mCount += 1;

if (mLogRecords.size() < mMaxSize) {

mLogRecords.add(new LogRec(msg, messageInfo, state, orgState));

} else {

LogRec pmi = mLogRecords.get(mOldestIndex);

mOldestIndex += 1;

if (mOldestIndex >= mMaxSize) {

mOldestIndex = 0;

}

pmi.update(msg, messageInfo, state, orgState);

}

}

}

private static class SmHandler extends Handler {

/** The debug flag */

private boolean mDbg = false;

/** The SmHandler object, identifies that message is internal */

private static final Object mSmHandlerObj = new Object();

/** The current message */

private Message mMsg;

/** A list of log records including messages this state machine has processed */

private LogRecords mLogRecords = new LogRecords();

/** true if construction of the state machine has not been completed */

private boolean mIsConstructionCompleted;

/** Stack used to manage the current hierarchy of states */

private StateInfo mStateStack[];

/** Top of mStateStack */

private int mStateStackTopIndex = -1;

/** A temporary stack used to manage the state stack */

private StateInfo mTempStateStack[];

/** The top of the mTempStateStack */

private int mTempStateStackCount;

/** State used when state machine is halted */

private HaltingState mHaltingState = new HaltingState();

/** State used when state machine is quitting */

private QuittingState mQuittingState = new QuittingState();

/** Reference to the StateMachine */

private StateMachine mSm;

/**

  • Information about a state.

  • Used to maintain the hierarchy.

*/

private class StateInfo {

/** The state */

State state;

/** The parent of this state, null if there is no parent */

StateInfo parentStateInfo;

/** True when the state has been entered and on the stack */

boolean active;

/**

  • Convert StateInfo to string

*/

@Override

public String toString() {

return “state=” + state.getName() + “,active=” + active

  • “,parent=” + ((parentStateInfo == null) ?

“null” : parentStateInfo.state.getName());

}

}

/** The map of all of the states in the state machine */

private HashMap<State, StateInfo> mStateInfo =

new HashMap<State, StateInfo>();

/** The initial state that will process the first message */

private State mInitialState;

/** The destination state when transitionTo has been invoked */

private State mDestState;

/** The list of deferred messages */

private ArrayList mDeferredMessages = new ArrayList();

/**

  • State entered when transitionToHaltingState is called.

*/

private class HaltingState extends State {

@Override

public boolean processMessage(Message msg) {

mSm.haltedProcessMessage(msg);

return true;

}

}

/**

  • State entered when a valid quit message is handled.

*/

private class QuittingState extends State {

@Override

public boolean processMessage(Message msg) {

return NOT_HANDLED;

}

}

/**

  • Handle messages sent to the state machine by calling

  • the current state’s processMessage. It also handles

  • the enter/exit calls and placing any deferred messages

  • back onto the queue when transitioning to a new state.

*/

@Override

public final void handleMessage(Message msg) {

if (mDbg) Log.d(TAG, “handleMessage: E msg.what=” + msg.what);

/** Save the current message */

mMsg = msg;

if (mIsConstructionCompleted) {

/** Normal path */

processMsg(msg);

} else if (!mIsConstructionCompleted &&

(mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {

/** Initial one time path. */

mIsConstructionCompleted = true;

invokeEnterMethods(0);

} else {

throw new RuntimeException("StateMachine.handleMessage: " +

"The start method not called, received msg: " + msg);

}

performTransitions();

if (mDbg) Log.d(TAG, “handleMessage: X”);

}

/**

  • Do any transitions

*/

private void performTransitions() {

/**

  • If transitionTo has been called, exit and then enter

  • the appropriate states. We loop on this to allow

  • enter and exit methods to use transitionTo.

*/

State destState = null;

while (mDestState != null) {

if (mDbg) Log.d(TAG, “handleMessage: new destination call exit”);

/**

  • Save mDestState locally and set to null

  • to know if enter/exit use transitionTo.

*/

destState = mDestState;

mDestState = null;

/**

  • Determine the states to exit and enter and return the

  • common ancestor state of the enter/exit states. Then

  • invoke the exit methods then the enter methods.

*/

StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);

invokeExitMethods(commonStateInfo);

int stateStackEnteringIndex = moveTempStateStackToStateStack();

invokeEnterMethods(stateStackEnteringIndex);

/**

  • Since we have transitioned to a new state we need to have

  • any deferred messages moved to the front of the message queue

  • so they will be processed before any other messages in the

  • message queue.

*/

moveDeferredMessageAtFrontOfQueue();

}

/**

  • After processing all transitions check and

  • see if the last transition was to quit or halt.

*/

if (destState != null) {

if (destState == mQuittingState) {

/**

  • Call onQuitting to let subclasses cleanup.

*/

mSm.onQuitting();

cleanupAfterQuitting();

} else if (destState == mHaltingState) {

/**

  • Call onHalting() if we’ve transitioned to the halting

  • state. All subsequent messages will be processed in

  • in the halting state which invokes haltedProcessMessage(msg);

*/

mSm.onHalting();

}

}

}

/**

  • Cleanup all the static variables and the looper after the SM has been quit.

*/

private final void cleanupAfterQuitting() {

if (mSm.mSmThread != null) {

// If we made the thread then quit looper which stops the thread.

getLooper().quit();

mSm.mSmThread = null;

}

mSm.mSmHandler = null;

mSm = null;

mMsg = null;

mLogRecords.cleanup();

mStateStack = null;

mTempStateStack = null;

mStateInfo.clear();

mInitialState = null;

mDestState = null;

mDeferredMessages.clear();

}

/**

  • Complete the construction of the state machine.

*/

private final void completeConstruction() {

if (mDbg) Log.d(TAG, “completeConstruction: E”);

/**

  • Determine the maximum depth of the state hierarchy

  • so we can allocate the state stacks.

*/

int maxDepth = 0;

for (StateInfo si : mStateInfo.values()) {

int depth = 0;

for (StateInfo i = si; i != null; depth++) {

i = i.parentStateInfo;

}

if (maxDepth < depth) {

maxDepth = depth;

}

}

if (mDbg) Log.d(TAG, “completeConstruction: maxDepth=” + maxDepth);

mStateStack = new StateInfo[maxDepth];

mTempStateStack = new StateInfo[maxDepth];

setupInitialStateStack();

/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */

sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));

if (mDbg) Log.d(TAG, “completeConstruction: X”);

}

/**

  • Process the message. If the current state doesn’t handle

  • it, call the states parent and so on. If it is never handled then

  • call the state machines unhandledMessage method.

*/

private final void processMsg(Message msg) {

StateInfo curStateInfo = mStateStack[mStateStackTopIndex];

if (mDbg) {

Log.d(TAG, "processMsg: " + curStateInfo.state.getName());

}

if (isQuit(msg)) {

transitionTo(mQuittingState);

} else {

while (!curStateInfo.state.processMessage(msg)) {

/**

  • Not processed

*/

curStateInfo = curStateInfo.parentStateInfo;

if (curStateInfo == null) {

/**

  • No parents left so it’s not handled

*/

mSm.unhandledMessage(msg);

break;

}

if (mDbg) {

Log.d(TAG, "processMsg: " + curStateInfo.state.getName());

}

}

/**

  • Record that we processed the message

*/

if (mSm.recordLogRec(msg)) {

if (curStateInfo != null) {

State orgState = mStateStack[mStateStackTopIndex].state;

mLogRecords.add(msg, mSm.getLogRecString(msg), curStateInfo.state,

orgState);

} else {

mLogRecords.add(msg, mSm.getLogRecString(msg), null, null);

}

}

}

}

/**

  • Call the exit method for each state from the top of stack

  • up to the common ancestor state.

*/

private final void invokeExitMethods(StateInfo commonStateInfo) {

while ((mStateStackTopIndex >= 0) &&

(mStateStack[mStateStackTopIndex] != commonStateInfo)) {

State curState = mStateStack[mStateStackTopIndex].state;

if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());

curState.exit();

mStateStack[mStateStackTopIndex].active = false;

mStateStackTopIndex -= 1;

}

}

/**

  • Invoke the enter method starting at the entering index to top of state stack

*/

private final void invokeEnterMethods(int stateStackEnteringIndex) {

for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {

if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());

mStateStack[i].state.enter();

mStateStack[i].active = true;

}

}

文末

架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。

移动架构师

系统学习技术大纲

一线互联网Android面试题总结含详解(初级到高级专题)

image

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Info curStateInfo = mStateStack[mStateStackTopIndex];

if (mDbg) {

Log.d(TAG, "processMsg: " + curStateInfo.state.getName());

}

if (isQuit(msg)) {

transitionTo(mQuittingState);

} else {

while (!curStateInfo.state.processMessage(msg)) {

/**

  • Not processed

*/

curStateInfo = curStateInfo.parentStateInfo;

if (curStateInfo == null) {

/**

  • No parents left so it’s not handled

*/

mSm.unhandledMessage(msg);

break;

}

if (mDbg) {

Log.d(TAG, "processMsg: " + curStateInfo.state.getName());

}

}

/**

  • Record that we processed the message

*/

if (mSm.recordLogRec(msg)) {

if (curStateInfo != null) {

State orgState = mStateStack[mStateStackTopIndex].state;

mLogRecords.add(msg, mSm.getLogRecString(msg), curStateInfo.state,

orgState);

} else {

mLogRecords.add(msg, mSm.getLogRecString(msg), null, null);

}

}

}

}

/**

  • Call the exit method for each state from the top of stack

  • up to the common ancestor state.

*/

private final void invokeExitMethods(StateInfo commonStateInfo) {

while ((mStateStackTopIndex >= 0) &&

(mStateStack[mStateStackTopIndex] != commonStateInfo)) {

State curState = mStateStack[mStateStackTopIndex].state;

if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());

curState.exit();

mStateStack[mStateStackTopIndex].active = false;

mStateStackTopIndex -= 1;

}

}

/**

  • Invoke the enter method starting at the entering index to top of state stack

*/

private final void invokeEnterMethods(int stateStackEnteringIndex) {

for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {

if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());

mStateStack[i].state.enter();

mStateStack[i].active = true;

}

}

文末

架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。

[外链图片转存中…(img-UyhAsZ8F-1714211876137)]

[外链图片转存中…(img-Lyb7cEOc-1714211876138)]

一线互联网Android面试题总结含详解(初级到高级专题)

[外链图片转存中…(img-JGAARmrY-1714211876138)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值