Android stateMachine分析
StateMachine与State模式的详细介绍可以参考文章:Android学习 StateMachine与State模式
下面是我对于StateMachine的理解:
先了解下消息处理。看下StateMachine::sendMessage方法。
不管BT/Wifi中,都有继承StateMachine的子类(BluetoothAdapterStateMachine.java/WifiStateMachine.java),在某些类中,会创建这些类的对象,当需要发送消息时,会调用它们的sendMessage方法,即调用父类StateMachine的sendMessage方法。
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return; mSmHandler.sendMessage(obtainMessage(what));
} /**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return; mSmHandler.sendMessage(obtainMessage(what,obj));
} /**
* Enqueue a message to this state machine.
*/
public final void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
if (mSmHandler == null) return; mSmHandler.sendMessage(msg);
}
从sendMessage方法中可以看到,实际上是调用了StateMachine::SmHandler::sendMessage方法,该类没有实现该方法,所以会调用父类Handler::sendMessage方法,然后会调用StateMachine::SmHandler::handleMessage方法进行处理:
/**
* 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); //1
} 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(); //2 if (mDbg) Log.d(TAG, "handleMessage: X");
}
该方法中有两个重要的方法:
1.processMsg(msg);
/**
* 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());
}
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
if (isQuit(msg)) {
transitionTo(mQuittingState);
}
break;
}
if (mDbg) {
Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
}
} /**
* Record that we processed the message
*/
if (mSm.recordProcessedMessage(msg)) {
if (curStateInfo != null) {
State orgState = mStateStack[mStateStackTopIndex].state;
mProcessedMessages.add(msg, mSm.getMessageInfo(msg), curStateInfo.state,
orgState);
} else {
mProcessedMessages.add(msg, mSm.getMessageInfo(msg), null, null);
}
}
}
这个方法中有一个while循环,看下条件:curStateInfo.state.processMessage(msg),即调用当前状态(State具体的子类)的processMessage方法。在具体实现的State子类中,在processMessage方法中,在具体的case处理完message后,会返回true 或 false(true的话会使得上述代码中的while循环退出,即该消息不上传给父状态处理,自己处理完就好了;false的话,就是再上传给父状态处理)。
2.performTransitions();
/**
* 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) {
cleanupAfterQuitting(); } else if (destState == mHaltingState) {
/**
* Call halting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.halting();
}
}
}
这个方法主要是完成:
1.当前状态的切换,
2.更新状态栈。
比如状态已经通过addState方法添加完毕,形成了树形结构。当前状态是S4,现在要切换到S5。performTransitions方法中会完成一项功能:pop S4 S1,push S2 S5。

Android stateMachine分析的更多相关文章
- Android多线程分析之五:使用AsyncTask异步下载图像
Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...
- Android多线程分析之四:MessageQueue的实现
Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...
- Android多线程分析之三:Handler,Looper的实现
Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...
- Android多线程分析之二:Thread的实现
Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一 ...
- Android多线程分析之一:使用Thread异步下载图像
Android多线程分析之一:使用Thread异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 打算整理一下对 Android F ...
- Android Launcher分析和修改13——实现Launcher编辑模式(1) 壁纸更换
已经很久没更新Launcher系列文章,今天不分析源码,讲讲如何在Launcher里面添加桌面设置的功能.目前很多第三方Launcher或者定制Rom都有简单易用的桌面设置功能.例如小米MIUI的La ...
- Android Launcher分析和修改9——Launcher启动APP流程
本来想分析AppsCustomizePagedView类,不过今天突然接到一个临时任务.客户反馈说机器界面的图标很难点击启动程序,经常点击了没有反应,Boss说要优先解决这问题.没办法,只能看看是怎么 ...
- 正确使用Android性能分析工具——TraceView
http://blog.jobbole.com/78995/ 首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他技术 - 导航条 - 首页 最新文章 IT 职场 前端 - Ja ...
- Android架构分析之Android消息处理机制(二)
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本号:4.4.2 在上一篇文章中我们看了一个使用Handler处理Message消息的样例,本文我们 ...
随机推荐
- 第二章:RESTful API
学习内容 使用Spring MVC编写Restful API 使用Spring MVC处理其他web应用常见的需求和场景 如何处理静态资源和异常,如何使用Spring MVC的拦截器,文件的上传下载, ...
- flask中的request
1.request是什么? 简单来说,它就是flask的封装的一个对象,这个对象包含着前端请求所带的所有信息.既然说它是一个对象,那么它肯定是有一些熟悉,和方法的,下面就来介绍下request里的熟悉 ...
- Linux运维一定要知道的六类好习惯和23个教训,避免入坑!
Linux运维一定要知道的六类好习惯和23个教训,避免入坑! 从事运维三年半,遇到过各式各样的问题,数据丢失,网站挂马,误删数据库文件,黑客攻击等各类问题. 今天简单整理一下,分享给各位小伙伴. 一. ...
- centos7-mongodb3.4.6集群的搭建
0.需要环境 安装包:mongodb-linux-x86_64-3.4.6.tgz 安装路径:/usr/mongodb 服务器: 192.168.177.131/132/133 mongos 2000 ...
- JS学习- ES6 async await使用
async 函数是什么?一句话,它就是 Generator 函数的语法糖. 使用场景常常会遇到,请求完一个接口,拿完值再去请求另外一个接口,我们之前回调callback函数处理,如果很多的情况下,看起 ...
- 使用百度定位Api获取当前用户登录地址
最近在做一个商城项目,客户想把网站做成类似于美团的效果,切换地区时,内容也跟随变化.这就要首先解决根据用户id获得地址的问题,最终决定使用百度定位(不适用于搭建反向代理的项目) String url ...
- PHP接收http请求头信息
1.PHP 自带函数 getallheaders() 目前 getallheaders() 只能用于 apache 中.如果想在 nginx 中也能使用,可以使用自定义函数. foreach (get ...
- 强化记忆之php
php 输出的区分 新手摸索道路,有说不对的地方,还请多多包涵. echo 能够输出一个以上的字符串,也能输出html标签 print 一次只能接受一个字符串(区分与echo),也能输出html标签 ...
- vm 中 centOS 7 固定ip设置
虚拟机中,centOS通过NAT连接,设置固定IP上网. 本地主机 VMware Network Adapter VMnet8 状态信息: 描述: VMware Virtual Ethernet A ...
- 最简单的bootloader的编写
目标:写出bootloader的第一阶段代码和第二阶段代码,并测试. 最简单的bootloader的编写步骤: 1. 初始化硬件:关看门狗.设置时钟.设置SDRAM.初始化NAND FLASH2. 如 ...