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 optionallyenter/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 currentprocessingMessage
-
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 callexit
of the current state and its parents, call -
onQuiting
and then exit Thread/Loopers. -
In addition to
processMessage
eachState
has -
an
enter
method andexit 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
. ThesendMessageAtFrontOfQueue
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面试题总结含详解(初级到高级专题)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!