activity 和 生命周期 :流程

  activity是android的一个基本的组件。讨论生命周期,taskstack等等的话题的时候。就不得不去看一下android framework层的源码了。

  生命周期,实际就是系统调用android代码的时候做的回调函数,复写之后,就会和android app运行为一体。简单的来说,和activity有关的类有很多。其中和生命周期有关的,就是管理activity的类。包括activityThread,activityManagerNative,activityManagerService 和activityStack:

  activityThread: 每一个java程序都有一个main函数,android也不例外。每一个app都是一个进程,这里既是一个app的起始点。gui的编程无非就是在循环中不断的读取消息,然后处理消息。这里的消息包括了各种系统定义的消息,还有ui的消息。activityThread里面有一个H内部类(就是Handler),这里面就定义了各种的消息处理,包括各个生命周期函数的方法调用消息:LAUNCH_ACTIVITY,PAUSE_ACTIVITY等等。

tip:为什么会有H内部类?假如有了这个疑问,就是没有体会gui编程的本质。消息循环,android开发我感觉弱化了这一概念。假如没有消息循环,窗口就不能判断各种事件,不能作出处理。细想一下,只有响应式的这种设计,才是gui编程的基本原理。没有其他可以代替。所以Handler处理的消息机制是android ui运行的基本ok,这个毋庸置疑了。H存在是合理的不可替代的。为什么会有activityThread?他的出现实际上就是作为消息循环的框架出现的。管理了框架中的各个元件的管理和生成,android4大基本组件activity,service,provider都在activityThread中管理。所以activityThread存在是必然的。

  activityManagerNative和activityManagerService:他两个出于不同的包里面,一个是core的app下,一个是services的am包下。来说一下,activityManagerService是zygote创建系统服务,也就是说这个服务和我们的android app是两个进程之间。android的ipc通信使用的是binder机制。这个机制也是android的核心之一,也就是通过activityManagerNative调用了activityManagerService里面的方法,调用了系统功能。

tip:他两的存在性就不必强调了,多任务系统的进程通信一直都是值得关注的问题。而binder机制提供了这种功能。这两个类的作用就是使得app和系统更加有序的交互。

  activityStack:栈,是的这个就是activity栈,他也在系统服务包中,说明这个栈管理的是所有的activity的功能。所有的存在的activity都会存储在这个栈中,里面有历史栈,resume栈等,保存着各种的activity操作信息。

tip:activitystack由于android程序一般都是占满屏幕的,所以切换不易,必须要有一种操作的规律和习惯。栈是人们潜意识中很认可的一种结构,android是基于linux支持多进程很好。windowphone7.5的时候就一般了,而且操作很不习惯。玩了很久才弄明白。但不得不说metro风格确实是一大亮点。

解释完这些,我们就了解了android activity的生成过程,细想一下,是通过intent开开启activity的,调用了startActivity,有一个activity的默认操作类Instrumentation来调用了activityManagerNative,然后通过binder调用activityManagerService的方法调用activitystack的管理方法添加activity,启动actvityThread,然后发送消息给H进行显actvity。

  在说说生命周期,整个期间是如何进行回调的?其中的调用过程十分复杂,我想我必须研究的足够的时候在写其中的奥妙,可是还是没有完。遇到了一个问题就是在oncreate中想得到view的宽高。网络上有很多方法,但是只有知道系统的调用原理和流程,才会理解为什么那样做。

  首先不说如何解决?说一下为什么oncreate中得不到view的宽高?都知道view绘制有3步:测量,布局,绘制。也就是oncreate的时候view就没有做这几个步骤。那setcontentview中做了什么?

回到生命周期:

  onreate和ondestory中是指activity被创建了,也就是初始化的时候的回调,这个时候做的都是初始化工作,setcontentview也仅仅就是解析xml然后进行了view的创建。但是布局和大小信息都不确定。

  onstart和onstop中指的activity被显示,这个看似是很鸡肋的,我们都没有多使用过,确实,这个时期,就是显示了actvity的窗口,activity可视了。这时候可以layout测绘了?没有,这时候显示的是除了我们setcontentview里面布局之外的东西,也就是有一个actionbar和一个白色背景,当然这要看你的布局是怎么定义的了。这算什么意思?这些布局不都是一起的吗?为什么没有我设置的?细细想,还确实不是一起的,先不谈phonewindow和decorview,我们定义过titlebar没有?没有,这是系统的,实际上这一时期是为了显示activity的,不做其他的。

  onresume和onpause指activity在可以交互,坑爹的时刻到了,大多数人认为这个时期一定是加载了我们的布局,实际上在这个时期是要使得布局和前台进行交互,但是在布局测绘之前系统回调了onresume,导致很多人认为onresume之前一定有layout的测绘信息,这个是错误的。你可以查看源码activityThread中关于handleResumeActivity里面的源码,最后调用了activity的makeVisible进行了view的显示。也就是说这一个时刻仅仅是告诉我们actvity要到前台交互的时候了,千万不可和布局的东西混为一谈。

  这也就说明了为什么会出现之前的问题,这时候怎么办?所有生命周期的函数都没有在layout的时候调用的,没有生命周期的函数,我们还有回调函数,其实view有一个getViewTreeObserver,可以再viewtree的回调函数中进行值的获取,这种方式是可行的,也就是等到测绘layout之后在进行取值,当然还有一种就是自己进行测绘,利用measure,有的人说不行,实际上他根本就不会使用measure,MeasureSpec是其中的关键,他如何利用一个int来表示了模式和大小两个状态,不明白一共有3种模式,一味的递参数(0,0)那么只能呵呵了。这种方式是可行的,我会在以后view的绘制中专门叙述这些概念。

  其实我是想说另一种方式,我在网上没有看到,可能有人实现过。就是使用view.post来进行一个把runnable的方法放到主线程中运行,这个方法可行吗?其关键就是这个代码什么时候执行?是立刻?不是,既是在oncreate中使用这个也会在onresume之后运行,这实际上把一个消息放入消息循环中,由于消息队列是阻塞式的,当执行完所有的显示activity的方法之后才会执行这个消息。做了大量的实验。证明这一点事毋庸置疑的,所以我认为系统创建的消息包括launchactvity和resumeactivity的一些消息一定是view.post这条消息之前的,实际上我尝试源码中的证据,你可以看到的是只看到了H.LAUNCH_ACTIVITY这一个消息(虽然也有H.RESUME_ACTIVITY但是在初始创建期间不会调用),也就是说这个消息处理函数handleLaunchActivity里面执行完了oncreate,就接着执行了onstart和onresume一系列的生命周期函数,并不是每一个回调都作为一个消息。这的理由是合理的:1.你不必使用多个消息,应为这个过程本身就是连续的(当然我指的连续不是代码上的连续,而是逻辑上的连续)。2.这也就是解释了为什么在oncreate里面提交的消息,会在onresume之后执行。

  当然这个问题就算解决了,应该思考的不是这个问题,而是android的这些生命周期的是如何协调的?可以看到生命周期是和用户交互最为紧密的。我会在研究源码的同时把后续blog写出来。

上一篇:TestNG之注解的生命周期


下一篇:SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第3部分)(完结)