Processes and Threads life cycle生命周期

来源:互联网 发布:广州市知用中学分数线 编辑:程序博客网 时间:2024/04/28 15:16

Processes and Threads

However, you can arrange for components to run in other processes, and you  can spawn additional threads for any process.

当一个应用程序的第一个component需要运行时,Android为它启动一个包含一个线程的Linux进程。默认情况下,一个应用程序中所有的component都在该进程和线程中运行。

你也可以让component在其他的进程中运行或者在进程中创建其它的线程。

Processes

一个component在进程中运行,该进程是被manifest文件所控制的。component元素 — <activity>, < service>, <receiver>, <provider> — 每一个都有一个process属性来指定该component运行的位置。这些属性可以被设置成每个component在各自不同的进程中运行,或者某些component在同一个进程中运行。它们也可以被设置成不同的应用程序的component在同一个进程中运行 — 只要这些应用程序共用同一个Linux user  ID。<application>元素也有一个process属性用来设置所有component的默认属性值。

所有的component都在一个进程中的主线程中初始化,对component的系统调用是由该线程调度的。对每一个实例有不同的线程。因此,实例方法 — 例如View.onKeyDown()这样的报告用户动作和生命周期通知的方法 — 永远在主线程中运行。这意味着component不应该做耗时的和阻塞的操作,而是应该创建其它的线程来做。

Android可以决定在资源不足时关闭一个进程。在进程内运行的应用程序的component随之关闭。当有事情要做时,一个进程又会启动。

Android在决定关闭哪个程序时会计算它们对用户的相对重要性。例如,不可见的程序比可见的重要性低。因此是否关闭一个进程的决定取决于component的状态,下一节我们讨论之。

Threads

即时你可以将应用程序限制在一个单个进程中,有可能你也需要启动一个线程来做一些后台工作。由于用户界面需要永远快速响应,负责activity的线程不应做耗时多的工作。这些工作应该放在另一个线程中做。
线程使用Java  Thread对象在代码中创建。Android提供了一些类来方便管理线程 — Looper用来在线程中运行一个消息循环,Handler用来处理消息,HandlerThread用来在消息循环中设置一个线程。

Remote procedure calls

Android有一个轻量级的RPC机制。在这里一个方法在本地调用,但在远程执行(在另一个进程中),再将结果返回给调用者。这要求将方法调用和它的数据分解到操作系统可以理解的级别,将其从本地进程和地址空间转移到远程进程和地址空寂那,然后重新组织和调用。返回值必须从相反的方向传送。Android提供了做这些事情的代码,所以你可以集中精力来定义和实现RPC接口本身。

一个RPC接口可以只包含方法。所有的方法都是同步运行(本地方法阻塞直到远程方法完成),即使没有返回值。简而言之,该机制如下:首先使用IDL(interface  definition  language)定义一个RPC接口。aidl工具从这个声明来生成一个Java接口定义,该定义对本地和远程进程都有效。它包含两个内部类,如下图所示:



内部类具有管理在IDL中定义的rpc接口的代码。两个内部类均实现IBinder接口。其中一个是系统本地内部调用的,另外一个成为Stub的扩展了Binder类。除了IPC调用的内部代码外,它还包含RPC接口的声明。你需要继承Stub来实现这些方法,如图所示。

一般的,这些远程进程将被一个服务来管理(因为一个服务可以通知系统一个进程和其他进程的连接)。该服务既有aidl工具生成的接口文件又有实现RPC方法的Stub的子类。该服务的客户将只有aidl工具生成的接口文件。

下面是一个service和一个client建立连接的过程:

  • service的client(在本地端)实现onServcieConnected()和onServiceDisconnected()方法,这样它们就可以在连接成功和断开成功后被通知。它们可以通过bindService()来建立连接。
  • service的onBind()方法将接受或拒绝连接,根据它接收到的intent(发送给bindService()的intent)。如果连接接受了,它将返回一个Stub类的实例。
  • 如果service接受了连接,Android调用client的onServiceConnected()方法并将其传给一个IBinder对象 —   由service管理的Stub子类的一个代理。通过该代理,client可以调用远程方法。

Component Lifecycles

应用程序的component有生命周期—从一开始Android初始化它们使它们响应intent到结束时它们被销毁。在其间,它们有时候有效有时候无效,对于activity来说,有时候对用户可见有时候不可见。本节讨论activity,service以及broadcast  receiver的生命周期——包括它们可能处于的状态,在状态转换时通知你的方法,和这些状态对进程的终止和实例销毁的作用。

Activity lifecycle

Activity有三种基本状态:

  • 当它在屏幕前台时(出于当前task的activity stack的顶端)状态为active或running。该activity是用户动作的焦点。  
  • 如果它失去焦点但仍然对用户可见,它的状态为paused。也就是说,另一个activity位于其顶端,并且那个activity是透明的或者未覆盖整个屏幕,因此该暂停的activity仍然有一部分可见。一个暂停的activity完全是活着的(它保存了所有的状态和成员信息并且和窗口管理器连接),但是可以在极端内存不足时可以被系统关闭。  
  • 当它被另一个activity完全覆盖时状态为stopped。它仍然保存了所有的状态和成员信息。然而,它对用户是不可见的因此它的窗口被隐藏了,并且在系统在其它地方需要内存的时候常常kill掉它。
如果一个activity处于paused或stopped状态,系统可以将其从内存中去掉,可以告诉它关闭(调用它的finish()方法),或者直接kill掉它的进程。当它再次显示时,它必须完全重启并恢复到原来的状态。
当一个activity从一个状态转换到另一个状态,它会被通知,这是通过调用下面的函数完成的:

void onCreate(BundlesavedInstanceState)
void  onStart()
void onRestart()
void onResume()
void  onPause()
void onStop()
void onDestroy()

所有这些方法都可以被重写来做状态改变时应该做的工作。所有的activity必须实现onCreate()方法来做初始化工作。许多activity实现onPause()来确认数据修改并做好停止和用户交互的准备。

调用父类方法

activity的声明周期方法必须首先调用其父类版本。例如:
protected void onPause(){
    super.onPause();
     .. .
}

这7个方法一起定义了一个activity的生命周期。通过实现这些方法,你可以管理3个嵌套的生命周期循环:

  • 完整周期:从第一次调用onCreate()到一次onDestroy()。一个activity在onCreate()中做所有的"全局"状态的初始化设置,在onDestroy()中释放所有的资源。例如,如果它有一个后台线程从网络下载数据,它可以在onCreate()中创建该线程并在onDestroy()中停止该线程。
  • 可见周期:从一个onStart()到一个相应的onStop()。在这个周期内,用户可以在屏幕上看见该activity,虽然它不一定在前台与用户交互。在这两个方法之间,你可以维护显示activity所需要的资源。例如,你可以在onStart()中注册一个BroadcastReceiver来监视对UI有影响的变化,并在onStop()方法中将其unregister。onStart()和onStop()可以被调用很多次。
  • 前台周期:从一个onResume()到onPause()之间。在这期间,activity在所有其他屏幕上的activity之上并且在和用户交互。一个activity可以频繁的在resumed和paused状态之间切换——例如,onPause()在设备待机时或者当一个新的activity启动时被调用,onResume()在一个activity的返回值或者一个新的intent被发送的时候调用。因此,这两个方法中的代码应该是轻量级的。

下表阐述了这些循环以及activity状态转换的可能路径。彩色的椭圆为activity可以处于的状态。圆角矩形表示你可以实现的回调函数来实现在状态转换时进行的操作。

下表详细介绍这些方法的意义和在activity的生命周期中所处的地位:

方法描述是否能被kill下一个状态onCreate()当activity被创建时被调用。这里你应该做所有的静态初始化工作——创建view,绑定数据等等。该方法有一个Bundle对象保存了activity的前一个状态,如果该状态被获取。否onStart()onRestart()

当activity被stop以后,start之前。执行之后永远会执行onStart()。

否onStart()onStart()当activity变为对用户可见时被调用。如果activity进入前台则继续执行onResume(),如果它被隐藏则执行onStop()。否onResume()或onStop()onResume()当activity开始和用户进行交互时被调用。在这一个时间点activity处于activity       stack的顶端,处理用户输入。下一个状态永远为onPause()否
onPause()
onPause()当系统将要恢复另一个activity时调用。该方法一般用来保存一些数据,停止消耗cpu的操作例如动画等。它应该迅速完成工作,因为下一个activity要等到它返回才能恢复。如果该activity进入前台则继续调用onResume(),如果变为不可见则继续调用onStop().是onResume()或onStop()onStop()当activity对用户不再可见时调用。当activity被销毁或者另一个activity启动并覆盖于之上时调用。如果该activity回来和用户交互则调用onRestart(),如果该activity将被销毁则调用onDestroy()。是onRestart()或onDestroy()onDestroy()在activity被销毁之前被调用。这是activity最后一个接收的调用。它可以在activity正在结束时被调用(程序中调用了finish()),或者因为系统为节约空间而kill它。可以用isFinishing()方法来区分二者。是无


注意该表格的"是否能被kill"项。它表示系统是否能够在该方法返回后的任意时间Kill掉进程,而不执行该activity的其它代码。有三个方法onPause(),onStop()和onDestroy()该项为"是"。由于onPause()是3个中的第一个,因此它是唯一一个在进程被kill之前一定会被调用的—onStop()和onDestroy()可能不被调用。因此,你应该使用onPause()来保存任何永久性数据。

该项为"否"的方法在它们被调用时保护该activity进程不被Kill。因此一个activity的可Kill状态为从onPause()返回一直到onResume()被调用之前。直到下一次onPause()返回之前它都不能被kill。
在后面的进程和生命周期一节中会讲到,一个不处于可kill状态的activity仍然可以被系统kill掉——但只会发生在资源耗尽的极端的情况下。

Saving activity state

当系统,而不是用户关闭一个activity来节约内存时,用户可能希望当他们返回该activity时回到原来的状态。

为了保存activity被kill之前的状态,你可以实现一个onSaveInstanceState()方法。Android在销毁一个activity之前会调用这个函数——也就是说,在onPause()被调用之前。它传递一个Bundle对象给onSaveInstanceState(),在这个对象中你可以使用名字—数值对来记录activity的动态状态。当一个activity再次启动时,该Bundle对象被传递给onCreate()和onRestoreInstanceState()(该方法在onStart()之后调用)。这两个方法可以重新建立被保存的状态。

和onPause()等方法不同,onSaveInstanceState() 和 onRestoreInstanceState() 不是生命周期方法。它们不是总被调用。例如,Android在activity变为可以被系统销毁的状态时调用onSaveInstanceState(),但当该activity被用户销毁时不会调用(例如按下BACK键)。在这种情况下,用户不期望回到该activity,因此不需要保存它的状态。

因为onSaveInstanceState()不是总被调用,你应该只用它来记录activity的瞬时状态,而不是永久性数据。应该用onPause()来完成后者。

Coordinating activities

当一个activity启动另一个时,它们都会经历生命周期的转移。一个会暂停或停止,而另一个会启动。有时候,你需要协调这些activity。
生命周期回调函数的调用顺序是固定的,尤其当两个activity在同一个进程中时:
  1. 当前activity的onPause()方法被调用。
  2. 被启动的activity的onCreate(),onStart()和onResume()依次被调用。
  3. 如果前一个activity不再在屏幕上可见,则它的onStop()方法被调用。

Service lifecycle

一个service可以有两种用法:
  • 它可以被启动并允许一直运行直到有人停止它或者它自行停止。在这种模式下,它以Context.startService()方法来启动并使用Context.StopService()的方法来停止。它可以使用Service.stopSelf()或者Service.stopSelfResult()来停止自己。只需要一次stopService()方法就可以停止该service,无论startService()被调用了多少次。  
  • It can be operated programmatically using an interface that it defines and   exports. Clients establish a connection to the Service object and use that   connection to call into the service. The connection is established by calling   Context.bindService(), and is closed by calling Context.unbindService().   Multiple clients can bind to the same service. If the service has not already   been launched, bindService() can optionally launch it.

  • 它可以通过它定义的一些接口来程序化的操作。客户和Service对象建立一个连接并使用这个连接来调用service。该连接使用Context.bindService()来建立,并使用Context.unbindService()来断开。很多客户可以绑定同一个service。如果该service没有启动,bindService()可以可选的启动它。

这两种模式并非相互独立。你可以绑定一个由startService()启动的服务。例如,一个后台音乐服务可以由一个指定了需要播放音乐的intent对象使用startService()来启动。只在这以后,可能是当一个用户希望操作播放器或者获取当前歌曲信息,一个activity才会绑定到该service上。在这种情况下,stopService()直到最后一个连接断开才会将service停止。

和activity一样,service也有生命周期方法。但比较少,并且为public而不是protected:

void onCreate()
void onStart(Intent intent)
void onDestroy()

通过实现这些方法,你可以管理service生命周期的两个循环:

  • 完整周期:从onCreate()被调用直到onDestroy()返回。和activity一样,一个service在onCreate()中进行初始化,并在onDestroy()中释放所有资源。例如,一个音乐播放service可以在onCreate()中创建播放音乐的线程,并在onDestroy()中停止该线程。  
  • 活跃周期:该周期从onStart()被调用开始。被传给startService()的intent对象被传给该方法,音乐service查看该intent对象来播放其指定的音乐。

        service没有onStop()方法。

onCreate()和onDestroy()方法在所有service中都被调用。无论它们被Context.startService()还是Context.bindService()启动。但onStart()只会为由startService()启动的service调用。

如果一个service允许客户来绑定,有一些其它的方法需要实现:

IBinder onBind(Intent intent)
boolean  onUnbind(Intent intent)
void onRebind(Intent intent)

onBind()回调函数的参数intent对象就是bindService()所接受的intent对象,而onUnbind()中的intent对象是unbindService()接受的intent对象。如果该service允许绑定,则onBind()返回用户用来与service交互的信息通道。onUnbind()方法可以要求onRebind()在新的客户连接到service时被调用。
下表列出了一个service的回调函数。虽然它区分了使用startService和bindService启动的service,记住任何service,无论它是怎么启动的,都可以让客户绑定,因此任何service都可以接受onBind()和onUnbind()调用。

Broadcast receiver lifecycle

一个broadcast receiver只有一个回调方法:
void onReceive(Context curContext, Intent broadcastMsg)
当一个关于broadcast  receiver的广播消息到达时,android调用它的onReceive()方法并将包含消息的intent对象传递给它。broadcast  receiver只在它运行该方法时被认为是活跃的。当onReceive()返回时,它变为非活跃状态。
一个拥有活跃的broadcast  receiver的进程被保护不被kill。但是一个只有不活跃的的component的进程可以在任何时候被系统kill掉,当其它进程需要内存时。
这会引入一个问题:当一个广播消息的响应非常耗时间时,需要新建一个新的线程来运行该操作。如果onReceive()创建了这个线程并返回,则整个进程,包括新创建的线程会被认为是非活动的(除非有其它的component为活动的),该线程有可能会被kill掉。解决方案是用onReceive()启动一个service并让该service完成这个工作,那么系统直到这个进程仍然是活跃的。
下一节将进一步讨论进程被kill的可能性。

Processes and lifecycles

Android系统尝试尽可能长的维护一个应用程序进程,但最后它将在内存不足时把老的程序清除掉。为了决定哪些程序该保留、哪些程序应该kill,Android将每个进程放进一个重要性体系中,基于其中运行的component和它们的状态。重要性最低的进程最先被kill掉,以此类推。该体系中有5个等级:
  1. 一个前台进程是用户现在做的事情所需要的进程。一个进程满足下列任一条件即被认为是前台进程:
    • 它正在运行一个正在和用户交互的activity(该Activity对象的onResume()方法被调用)。
    • 它拥有一个被绑定到用户正在交互的activity上的service。
    • 它有一个service对象正在运行onCreate(),onStart()或onDestroy()中的一个。
    • It has a BroadcastReceiver object that's executing its onReceive()     method.

    • 他有一个BroadcastReceiver对象正在运行onReceive()方法。

    在某个时间,只有少数的前台进程会存在。它们只有在极端情况下被Kill——内存严重不足以至于它们不能都同时运行。一般的,在这个时间,设备达到了一个请求分页的状态,因此需要kill一些   前台进程来是用户界面能够响应。

  2. 一个可见进程为一个没有任何前台component但仍然能影响用户在屏幕上看到的内容的进程。一个进程满足下列任一条件则被认为是可见进程:  
    • 它持有一个activity,该activity不在前台,但仍对用户可见(它的onPause()方法被调用)。例如,一个前台activity为一个对话框,覆盖了后面一个activity。    
    • 它持有一个绑定到可见activity的service。

    一个可见进程被认为非常重要,只有在需要资源来让所有前台进程运行时才会被Kill掉。

  3. 一个服务进程是一个运行着使用startService()启动的service但并非前两种类型的进程。虽然服务进程并非直接和用户看见的东西绑定,它们一般来说正在进行用户关心的操作(例如在后台播放音乐或者下载网络数据),因此系统一般会让它们保持运行状态。  
  4. 一个后台进程是一个持有一个对用户不可见的activity的进程(Activity的onStop()方法被调用)。这些进程对用户体验没有直接影响,并且可以在任意时间被Kill以保证内存的需要。一般来说有很多后台进程在运行,因此它们被保存在一个LRU列表中来保证最近使用的拥有该activity的进程是最后kill的进程。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,kill该process将不会对用户体验造成不好的影响。

  5. 一个空进程未包含任何活动component的进程。保存这样一个进程的唯一原因就是用来提高下一次运行的速度。为了平衡系统资源,系统常常会清理掉这些进程。
Android将一个进程排在尽可能高的级别,基于其component的重要程度。例如,如果一个进程持有一个service和一个可见的activity,该process将被作为一个可见进程来排序,而不是一个服务进程。
另外,一个进程的排序可能因为其它进程对它的依赖性而上升。一个进程的优先级永远不低于它服务于的进程。例如,如果进程A中的一个content  provider服务于进程B中的一个客户,或者如果进程A中的一个service绑定到进程B中的一个component,则A至少和B一样重要。
由于正在运行一个服务的进程比拥有后台activity的进程排序高,因此一个启动一个长期运行的操作的activity可能会启动一个service来做这项工作,而不是启动一个线程——特别是如果该操作会比activity持续的更久的时候。例如播放背景音乐,上传照片等等。使用一个service保证了改操作将至少拥有服务进程的优先级,无论该activity发生了什么。就像前面所说的broadcast  receiver生命周期一样,这也是broadcast receiver应该使用service而不是线程来进行耗时操作的原因。
0 0