首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android自学札记:组件生命周期

2012-08-26 
Android自学笔记:组件生命周期Android应用程序组件中有一个生命周期,贯穿于创建到结束的整个周期。周期里面

Android自学笔记:组件生命周期
        Android应用程序组件中有一个生命周期,贯穿于创建到结束的整个周期。周期里面含有各种状态,这些状态对组件的生命周期起着至关重要的影响。

一、Activity生命周期
        1.Activity有三个状态
        (1)活动(active)或称运行(running):屏幕前台的Activity(当前任务中栈顶的Activity),用来处理当前用户的请求。
        (2)暂停(paused):指当前运行的Activity在屏幕上失去焦点但却对用户是可见的,也就是说用户能看得到它的界面,不过他是被当前Activity挡住了。暂停状态下的Activity仍是存活的(维持着所有状态和成员信息,屏幕上还会有它的窗体)。当前系统资源处于极度缺乏的情况下,这个状态下的Activity就会被干掉。
        (3)停止(stopped):屏幕不再有它的窗体,但是它仍然保留着所有状态和成员信息。通常当系统其它地方需要更多的内存时,这个Activity就会被干掉。
        2.如果一个Activity处于暂停或停止状态时,系统要么从内存中清除它要么调用它的finish()销毁它或是简单地干掉它的进程。当用户再次调用了这个Activity,它就会重新开始并保存住先前的状态。
        3.Activity的生命周期的转变本质上是其内部状态间的转变,Android提供了如下几个protect方法:

void onCreate(Bundle savedInstanceState) void onStart() void onRestart() void onResume() void onPause() void onStop() void onDestroy()
       
        4.以上方法均属钩子方法,我们需要重写它们,以使状态改变时做出恰当的行为。所有的Activity必须要重写onCreate(),因为这个方法用来做初始化和组装Activity的工作。大多数情况下,最好也要重写onPause()方法,主要是针对用户发出停止请求的情况下,我们需要在这个方法里面做一些处理(这一点很重要,下面会有所解释)。实现这些方法时需要注意一点,方法内部第一句话一定要先调用父类版本的方法,例如:
protected void onPause() {     super.onPause();}

        5.上面七个方法定义了Activity的整个生命周期,另外它们还有三个内嵌循环,如下:
        (1)Activity整体寿命(entire lifetime):这个循环发生在第一次调用onCreate()到最终调用onDestroy()期间。初始化工作在onCreate()中完成,释放所有剩余资源的工作在onDestroy()中完成。注意,这个循环过程是在同一线程中进行的。
        (2)Activity可见寿命(visible lifetime):这个循环发生在调用onStart()时直到调用onStop()期间。在这段时间里,尽管这个Activity不会和用户进行交互,但用户能够在屏幕上看到它;也就是说这两个方法维护着Activity所需要的一些资源(针对于用户)。这两个方法可以多次调用,比如对Activity进行来回显示或隐藏的操作。
        (3)Activity前台寿命(foreground lifetime):这个循环发生在调用onResume()时直到调用onPause()方法期间。在这段时间里,Activity在屏幕上是处于其他Activity的前面并与用户进行着交互。Activity会频繁地在暂停和重新状态之间相互转变。因此这两个方法中的代码需要做些轻量级的操作。

6.Activity生命周期图:

        上图详细阐述了Activity生命周期循环的路径,它们都是通过状态间的转换而形成的。带颜色椭圆是状态转换过程中涉及到最主要的活动,长方形就是那些回调方法。
        从上图就可以看出那七个方法它们在Activity生命周期中处于什么样的位置、每个方法又会有什么方法紧随其上下、当外部条件发生时,会使它们的状态发生怎样的变化,而这个变化带来的状态变化又会调用了哪些方法,通过此图一目了然。我们了解这些对于开发Android程序是大有裨益的,你很清楚你的程序是怎样的执行流程,在处理执行细节上也会游刃有余;那七个方法在开发程序时,再去看API介绍就会轻而易举地明了于心,同样也包括所有的API了。
        7.另外注意几点:
        (1)上文提到Android会在需要更多内存资源时干掉stopped和paused状态的Activity,但不会干掉它所调用的其它Activity进程。
        (2)上文曾提到除了重写onCreate(),还要顺便重写onPause()。说下原理:onPause()、onStop()、onDestroy()这三个方法都会引起Android关闭当前进程的情况出现,唯独onPause()能够在干掉当前进程之前被调用,其它两个方法都没这能力。换句话说,我们应该将涉及到链接外部的资源尽可能地干掉、用户未及时提交的数据要视情况再进行持久化的操作等等
        (3)上一条说到的那三个方法属于(杀手)方法,其余方法属于(CIA高官)方法,“杀手”一旦行动,不管成功与否都会告知那些“CIA高官”。也就是说Activity在执行任务时,只会属于一种角色,要不是“杀手”,要不是“CIA高官”;“杀手”通知Activity行动结束时,就转为“CIA高官”角色并执行它的任务(也就是搜索下一个要被“暗杀”的目标),一旦确定目标,就会通知“杀手”,整个角色转换过程就是这样。
        (4)在某种极端恶劣的情况下,比如系统实在没有其它资源了,那些不是被技术上定义成“killable”的Activity还是有可能被系统干掉的。
        8.有这么一种情况,系统(不是用户)为节省内存资源而关闭了一个Activity(也就是非正常关闭),当用户可能重新打开那个Activity时,期望出现的还是先前状态的界面。我们可以重写onSaveInstanceState()来捕捉被关闭掉的Activity之前的状态。
        9.保存Activity状态原理:Android会在某个极易被系统干掉的Activity前调用onSaveInstanceState(),也就是说会在onPause()前调用。这个方法接受一个Bundle对象的参数,你能以name-value键值对的形式记录住这个Activity的状态并存放进Bundle对象里面。 当这个Activity再次启动时,Bundle对象会传递给Oncreate()和onRestoreInstanceState()(它是在onstart()之后执行的),这两个方法都可以获取到先前捕捉的状态,以便重新创建Activity。
        10.onSaveInstanceState()和onRestoreInstanceState()与上面说到的那七个方法不同的是,它们不是总被调用,因此是没有生命周期的。举个例子来说:用户手动关闭了某个Activity(比如按下“回退”键),而你在应用程序中使用了保存状态的机制,这种情况下是没有任何意义的,反而对用户的使用上是不太方便的,因为用户不期望再次打开这个Activity时,还是关闭前的界面。Android建议我们在应对这种情况的时候,仅保存瞬时状态的数据,而不是那种持久化的数据,所以可以用onPause()来代替这种机制。
        11.再来说一种情况,一个Activity启动了另外一个Activity,它们都会经历生命周期的转变。当其中一个暂停或是停止时,而另外一个就开始。有时,我们需要协调好这些Activity,使它们能够正常的工作。生命周期中的回调规则有以下明确的定义,特别是两个Activity在统一进程中:
        (1)当前Activity的onPause()被调用;
        (2)下一个Activity的onCreate()、onStart()、onResume()按顺序依次执行。
        (3)然后,执行中的Activity在屏幕不可见时,就会调用它的onStop()方法。

二、Service生命周期
        1.Service生命周期有三个方法:
void onCreate() void onStart(Intent intent) void onDestroy()

        2.实现上面的三个方法,你能够监听Service生命周期的两个内嵌循环:
        (1)整体寿命(entire lifetime):这个循环发生在调用onCreate()时并终止于onDestroy()期间。同Activity一样,Service也是在onCreate()里面做初始化的操作,在onDestroy()里面做释放所有资源的操作。
        (2)活动寿命(active lifetime):这个循环起始于调用onStart()时。注意,这里没有只对应的onStop()。
        3.不管是Context.startService()还是Context.bindService()开启的Service,它们都会调用onCreate()和onDestroy();而onStart()只会被startService()调用。
        4.若以绑定的方式启动Service,Android提供了下面三个回调方法:
IBinder onBind(Intent intent) boolean onUnbind(Intent intent) void onRebind(Intent intent)

        onBind()返回客户端与Service交互通信的频道;若一个新的客户端连接了这个服务,onUnbind()则会调用onRebind()。
5 .Service生命周期图:

        上图详细阐述了Service的两种不同的生命周期,一个是通过startService()启动的,另一种是通过bindService()启动的。但请记住,任何Service不管它是怎么启动的,都会默许客户端绑定到它,因此可以在任何Service上调用onBind()和onUnBind()

三、Broadcast receiver生命周期
        1.Broadcast receiver生命周期中仅有一个回调方法:
void onReceive(Context curContext, Intent broadcastMsg)
当接收器接收到一条broadcast消息,Android就会调用onReceiver(),并传递给它一个Intent对象,这个对象携带着那条broadcast消息。我们认为仅当执行这个方式时,Broadcast receiver是活动的;这个方法返回时,它就终止了。这就是Broadcast receiver的生命周期。
        2 . 由于Broadcast receiver的生命周期很短,一个带有活动的Broadcast receiver的进程是受保护的,以避免被干掉;但是别忘了有一点,Android会在任意时刻干掉那些携带不再活动的组件的进程,所以很可能会造成这个问题。
        3 .解决上述问题的方案采用一个Service来完成这项工作,Android会认为那个进程中(Service所在的进程)仍然有在活动的组件。

四、进程和生命周期
        1.Android系统一直会维持着应用程序的进程,并让它们运行时间尽可能的长,但最终还是会因为系统内存资源不足时,干掉运行时间很长的进程。
        2.Android确定哪个进程是要继续运行还是将其干掉,它内部有个机制:将每个进程放置到“重要性层次”的序列中,这个层次序列依据运行中的组件和这些组件的状态而制定的;最低的当然是要被干掉,接下来依次排序逐一干掉它们。以下有五个层次级别:
        (1)前台进程(foreground process):用户当前操作的所需要的进程。当满足下列条件任意一条时,我们就认为它是前台进程:
                a)用户与在运行中的Activity(这个Activity中的onResume已经被调用过了)交互进行中。
                b)Service绑定到一个Activity上并且在与用户进行交互。
                c)执行Service生命周期的其中一个回调方法即可。
                d)执行了Broadcast receiver中的onReceiver()即可。
        (2)可见进程(visible process):该进程中没有任何的处于前台的组件,但用户仍然能在屏幕上能看到它们(说白了这种进程就是没在和用户交互罢了)。当满足下列条件任意一条时,我们就认为它是可见进程:
                a)Activity虽然不在前台(它的onPause()已经被调用过),但仍然对用户可见。举个例子:有一个Activity,它就是一个对话框,在某一时刻弹出了它;那先前的Activity就在对话框的后面了,也就是处于可见进程了。
                b)Service绑定到了一个可见状态的Activity上。
        (3)服务进程(service process):以startService()启动的Service,并非处于上面那两个高层次级别中。虽然Service没有用户界面,但是它所做的都是用户比较关心的事情(比如播放MP3或是网络下载)。当系统内存不足时,除了前两个级别,Service进程是会被系统干掉的。
        (4)后台进程(background process):该进程里面存在一个不再对用户可见的Activity(已经被调用onStop()),这些进程不会对用户体验产生任何影响。当系统为前三个级别的进程回收内存时,就要被干掉了。通常,应用程序中会有大量后台进程在运行,因此Android将它们放进LRU(至少最近被使用过:last recently used)列表中,以确保进程中的Activity的都是用户最近看到过的。如果某个Activity准确地实现了它的生命周期中的回调方法并捕获了当前的状态,当干掉它的进程时是不会对用户体验有任何影响的。
        (5)空进程(empty process):该进程中没有任何的活动应用组件。这个进程唯一的存在理由是当某个组件下次需要运行时,为了提高其启动时的速度提供了这么一个高速缓存的进程。Android系统经常会干掉这些进程,目的是为了平衡进程缓存和底层内核缓存中的系统资源。
        3.Android之所以划分这五个等级,目的就是让进程中重要性更高的应用组件得以运行,避免资源冲突情况。举个例子:某个进程中出现两个级别的组件,一个是Service,另一个是可见的Activity;该进程会运行那个可见的Activity,而不会去运行Service。
        4.另外,一个进程的排名也会因为其它依赖这个进程的进程而增加,也就是说,服务于其它进程的进程,永远不会比被服务的进程排名靠后。举个例子:一个content provider在进程A,客户端在进程B,A服务于B,或者,一个Service在进程A,它绑定到了进程B中的某个组件上;结论是:进程A永远是比进程B重要。
        5.我们来分析一下上面例子中的结论:某个进程中有个运行着的Service要比一个是后台进程的Activity的排名要靠前。换句话说,在Activity里面启动一个Service做那种长时间运行的操作要比简单地生成一个线程要好得多,特别是那些比Activity生命周期还要长的操作。例如在后台播放音乐、下载图片等操作。
        6.不管Activity发生了什么,运行中的Service会保证那些操作至少有“服务进程“的优先权。这个思路跟前面我们提到过的Broadcast receiver中采用Service方案解决被系统干掉的情况是一样的。



热点排行