位置: 编程技术 - 正文

Android StateMachine解析( 1 )

编辑:rootadmin

推荐整理分享Android StateMachine解析( 1 ),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

状态机模式可以帮助我们对复杂的软件行为进行建模,避免引入复杂的很多swich…case…或if…else…逻辑,导致代码很难维护。状态机构成的三要素是状态、消息和动作,即某个状态收到某条消息后执行某项动作(处理消息,若有需要执行状态迁移)。

Android在框架层定义的状态机类(frameworksbasecorejavacomandroidinternalutilStateMachine.java),其基于Android的Handler-Looper_Message机制构建。利用面向对象思想,进一步引入层次化(状态之间构成父子关系)状态机模型。父状态代表一种基本状态,子状态是包含了基本状态的特定状态。消息可以在子状态做细化具体处理,当子状态无法处理该消息时,就交给其父状态做基本处理(注意,这里的父状态和子状态在类定义上并不构成继承关系,他们均是状态的子类,即互相是兄弟类关系。他们只是在进入状态时或处理消息时具备传递链关系),以进一步减少代码冗余度

The state machine defined here is a hierarchical state machine which processes messages and can have states arranged hierarchically.

通过对Android StateMachine类的学习,我们可以进一步深入理解Android的Handler-Looper-Message机制的运用,并有助于我们利用状态模型建模。 先看看Android StateMachine对需求的定义: 当一个StateMachine被created和started之后,通过sendMessage()方法向StateMachine发送消息,消息通过Message.obtainMessage创建,当一个状态机收到消息之后,当前状态的processMessage方法会被调用。 StateMachine里面的每个状态都有零个或一个父状态,如果子状态无法处理这个消息,那么子状态的processMessage方法返回false或者NOT_HANDLED,接下来该条消息就会交给父状态的processMessage执行,这样延续下去,如果所有状态都未处理该消息,那么状态机的unhandledMessage方法会被调用,用来给消息最后一次执行机会。 当所有状态都被初始加入状态机并设定好层次(父子关系)后,跳转到一个新的状态会导致当前状态及其祖先状态的退出且新状态及其祖先状态的进入。如果当前状态和新状态具有共同的祖先状态,则当前状态一直到共同祖先状态间(不含共同祖先状态)的exit方法会被调用,然后又从共同祖先到新状态间的子状态开始一直到新状态,这些状态的enter方法也会被调用,并最终进入新状态。 当StateMachine构建好后,调用其start方法来启动状态机,启动后的第一个动作是从初始状态最顶层的祖先状态开始逐层调用enter方法。上述enter完成后接下来会进行消息队列中消息的处理。 StateMachine正常的退出,可以调用quit或者abort,调用quit会退出当前状态和他的父状态,调用onQuiting之后退出Thread和Looper。

主要相关类有State 、StateMachine 、 SmHandler(StateMachine的内部类)、 StateInfo(SmHandler的内部类)。

首先看看State类,这个类顾名思义,定义了状态本身,我们在开发活动中抽象的状态均可从该类派生,其主要有这样几个关键方法:

enter() //在进入状态时调用 exit() //在退出状态时调用 processMessage(Message) //当状态机处理消息时会调用当前状态的这个方法,

对StateMachine类,其下面几个方法:

Android StateMachine解析( 1 )

StateMachine() //构造函数中会构建出SmHandler(状态机处理器,后面会介绍),并将其与某个Looper绑定,根据构造函数参数的不同,也可能会构建出一个HandlerThread作为驱动状态机并提供Looper的线程。 addState()//通过SmHandler的同名接口向状态机添加状态,并指明添加状态的父状态(非类定义上的父子状态关系), setInitialState()//通过SmHandler的同名接口设置状态机的初始状态 getCurrentState() //通过SmHandler的同名接口获取当前状态 transitionTo()//通过SmHandler的同名接口执行状态迁移,使状态机当前状态发生切换 obtainMessage() //获取一条交给SmHandler的消息 sendMessage()//向SmHandler发送消息 deferMessage() //通过SmHandler的同名接口将消息推迟到下次状态迁移后进行消息处理,所有这些推迟的消息将放置到下次状态完成迁移后的消息队列前端优先处理。 sendMessageAtFrontOfQueue()//与deferMessage()相反,这个是通过SmHandler的同名接口将消息发送到消息队列的前端供当前状态优先处理。。 deferMessage和sendMessageAtFrontOfQueue这两个方法属于protected,只能在状态机及其子类中调用,不能被外部调用。 start() //启动状态机运行,实际上是通过SmHandler.completeConstruction()完成SmHandler的初始化,且发送一条SM_INIT_CMD消息。关于completeConstruction后面还会介绍。

SmHandler类

不难发现,上面的StateMachine类只是个对外暴露接口的封装代理类,真正的代码处理逻辑都是放在SmHandler这个类里面。 SmHandler类继承自Handler类,其内部还有个内部类名为StateInfo.先看看StateInfo的定义:

在SmHandler中,还基于数组维护了两个栈,这两个栈的初始化即在前面提到过的SmHandler.completeConstruction()方法中:

//基于初始化层次状态树的最大深度构建一个运行状态栈,这个栈顶标记的状态即为状态机当前运行状态,这个栈的主要用途是为了完成状态迁移(涉及到当前状态的父状态的退出和新状态及其父状态的退出)。位于这个栈上的状态均标记为活跃状态,即其active属性为true.

private StateInfo mTempStateStack[]; //在StateMachine初始化时,会将初始状态一直到它的顶级祖先状态通过mTempStateStack栈反序加入到mStateStack中,即最终初始状态顶级祖先状态会位于mStateStack栈底,而初始状态会位于mStateStack栈顶,在这之间是初始状态一直到顶级祖先状态的父状态。

另外还预定义了两个状态:

//挂起状态,当状态机挂起时进入 private HaltingState mHaltingState = new HaltingState(); //退出状态,当状态机退出时进入 private QuittingState mQuittingState = new QuittingState();

//不消说,继承自Handler类的SmHandler必然充定义了该消息处理方法,该方法的主要流程就是将消息交给mStateStack栈顶状态进行处理,如果栈顶状态不能处理该消息,就交给栈顶状态的父状态处理,一直这样延续下去直到消息被处理或父状态为空为止。如父状态为空消息都还未得到处理,就将调用unhandledMessage执行最后一次处理机会。

android studio 安装启动出现 The environment variable Java_home does not point to JVm。。 如果之前使用过eclipse开发android或者androidstudio开发android,那么很有可能是因为Java_home环境变量后面多了一个分号导致的。去掉分号试试

ViewPager禁止滚动 publicclassControllableViewPagerextendsViewPager{privatebooleanisCanScroll=true;publicControllableViewPager(Contextcontext){super(context);}publicControllableViewPager(Contextcontext,AttributeSetattrs

Android上电后的启动流程 本文翻译整理自:

标签: Android StateMachine解析( 1 )

本文链接地址:https://www.jiuchutong.com/biancheng/386817.html 转载请保留说明!

上一篇:Android界面开发(android 桌面开发)

下一篇:android studio 安装启动出现 The environment variable Java_home does not point to JVm。。(android studio 安装好后怎么在桌面找到)

  • 房地产开发企业简易计税方法 可以扣除吗
  • 小规模计提增值税
  • 代扣代缴增值税纳税义务发生时间
  • 应付销售方代垫的运费计入什么科目
  • 减值准备为什么影响利润总额
  • 什么经营范围可以开茶叶发票
  • 未使用固定资产计提折旧计入
  • 母公司捐赠资金给子公司
  • 汇算清缴纳税调整项目
  • 报表的应交税费都包含什么
  • 减免税金需要计提吗
  • 旧房转让土地增值税计算案例
  • 企业注销递延所得税资产怎么处理
  • 一般纳税人销售自己使用过的物品
  • 安保服务费税率几个点怎么算
  • 第一季度利润表本月数
  • 如何填制记账凭证总结
  • 境外个人所得税计算
  • 典当行的账务处理会计分录大全
  • 材料的盘点包括
  • 以前年度费用如何列支
  • 应付职工薪酬年底怎么结转
  • 工商年报中生育保险本期实际缴费金额
  • 房屋租赁合同变更
  • 给员工支付的房租怎么算
  • 网络平台的收入怎么算
  • linux用在哪些方面
  • 鸿蒙怎么添加
  • 消防工程改造需要什么资质
  • wamp搭建网站教程
  • 在linux中使用什么命令可以动态查看文件内容
  • 公司处于亏损状态,股东要退股怎么办
  • 采用销售额比率法预测对外筹资需要量时
  • 企业购买预付卡送人分录
  • 非常好看的头像
  • 2021年前端还火吗
  • 固定资产处置缴纳增值税政策依据
  • 赠送礼品账务处理会计分录
  • 进项税额转出需要补税
  • 典当公司收到房款怎么办
  • 个人所得税汇算清缴时间
  • 增值税差异调整
  • mongodb morphia
  • python 自定义异常
  • 一般纳税人购销合同印花税减免政策
  • 受托加工的物资属于资产吗
  • 消费税和资源税何时计入成本,何时计入费用
  • 企业清算是怎么做账的
  • 房屋租赁印花税计税金额含税吗
  • 企业对于无法收回的应收账款,应列入
  • 股权转让低于净资产的税怎么算
  • 普通发票红字冲销怎么操作流程
  • 税率由16%变更为13怎么算
  • 今年成立的公司需要申报残疾人保障金吗
  • 动态sql语句
  • sql server设置
  • mysql.sock在哪里
  • mysql存文章的字段设置为多大?
  • 无法使用ie浏览器
  • mac如何更换系统
  • bios设置从光驱启动优先,可是启动不了
  • windows系统后台不显示QQ等软件(任务栏右侧不显示QQ图标)
  • 怎样禁用ie
  • win7网络正常网页打不开是什么原因
  • win8开始界面如何设置成win7
  • linux如何查看用户的信息
  • win8一直配置更新
  • dos 批处理
  • css 网页布局
  • javascript:openattachment
  • 零基础搭建直播室与云直播平台
  • linux中mysql备份shell脚本代码
  • 几个常用的微课网站
  • 深圳市税务局好考吗
  • 上海市国家税务局地址
  • 纳税申报表如何打印
  • 发票怎样读入金税开票系统
  • 广东省社保局打印参保缴费凭证
  • 加强税务系统党委全面监督工作
  • 天津国税发票查询真伪查询
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设