Android应用程序由Java语言编写。Java代码被编译成Android Package文件(.apk)。一个.apk文件中的所有代码成为一个应用程序。
从很多方面来说,Android应用程序生活在他们自己的世界中:
可以让两个应用程序使用相同的user ID,则样它们可以看到对方的文件。为节约系统资源,拥有相同ID的应用程序也可以在相同的Linux进程中运行,共享一个虚拟机。
Android的一个核心特性就是:一个应用程序可以利用其它应用程序的元素。例如,如果你的应用程序需要显示图片,而有个人正好写了一个图片浏览程序,你可以直接去调用它。
为达到这个目的,当一个应用程序的任一部分需要启动时,系统都应该能够启动它。因此,Android的应用程序是没有唯一的程序入口的,而是有系统可以运行的基本component。component可以分为4种:
Activities
一个activity呈现了一个用户可以操作的可视化用户界面。例如,一个activity可以显示一个菜单列表或者显示一排图片。一个短信应用程序可以有一个显示联系人列表的activity,一个编辑信息的activity以及查看信息和设置的activity等等。一个应用程序可以由一个或多个activity组成。一般来说有一个activity是最先显示的。从一个activity转移到另一个activity是通过在一个activity中启动另一个activity来完成的。
每一个activity有一个某人的窗口可以绘图。一般来说,该窗口填满整个屏幕,但是它也可以比屏幕小。一个activity也可以使用额外的窗口 --- 例如一个弹出对话框。
一个窗口的内容是由view体系来提供的。每个view控制窗口内一个特殊的的矩形区域。父view包含并且控制子view的排列。树叶view在它们控制的矩形内绘画并且负责响应用户在它们负责区域内的动作。因此,view是activity和用户交互的区域。例如一个view可以显示一个图片,当用户点击它的时候完成一个动作。Android有许多内置的view --- 按钮、文本框,等等。
一个view的体系通过Activity.setContentView()被放置到一个activity的窗口中去。content view指的是在体系根部的view对象。(详见用户界面文档部分。)
Services
一个service不包含可见的用户界面,而是在后台无限地运行。例如,一个service可以在用户做其他事情时播放背景音乐,或者获取网络数据来供其它activity使用。service继承于Service类。
以一个从一个播放列表中播放歌曲的媒体播放器为例。播放器程序可能有一个或多个activity,使得用户可以选择歌曲和播放它们。然而,音乐的播放本身不能被一个activity来处理,因为用户希望它们离开播放器去做别的事情时音乐仍然在播放。为了使音乐不停播放,播放器activity可以启动一个后台service。系统可以让音乐播放service在启动它的activity离开屏幕时继续运行。
就像activity和其它的component一样,service在应用程序进程的主线程里运行。它们一般会启动另一个线程来做消耗时间的任务(例如音乐播放),从而不会阻塞其它的component和用户界面。(详见Processes and Threads).
Broadcast receivers
一个broadcast receiver是一个接收广播消息并作出回应的component。很多广播消息起源于系统代码 --- 例如,当时区变化、电池电量不足、刚刚拍了一张照片的时候都会产生消息广播。应用程序也可以产生广播消息 --- 例如,通知其它程序某些数据已经下载完成等等。
一个应用程序可以有任意多个broadcast receiver来响应它认为重要的消息。所有的receiver继承于BroadcastReceiver基类。
broadcast receiver没有界面。但是它可以启动一个activity来响应它们收到的信息,或者使用NotificationManager来警告用户。Notification有很多种:闪烁背光、震动、播放声音等等。一般来说它们在状态栏上有一个图标,在这个图标上显示消息。
Content providers
一个content provider使一个应用程序的某个数据集合可以为其他应用程序所用。这些数据可以存在文件系统中、SOLite数据库中或者其他地方。content provider继承于ContentProvider基类并实现一系列方法来使其他应用程序可以存取它控制的类型的数据。但是应用程序不会直接调用这些方法,而是使用一个ContentResolver对象来进行。一个ContentResolver可以和任何content provider来进行对话。它和content provider合作来管理进程间的通信。详见Content Provider文档。
当Android检测到有一个需要被某个component来处理的请求,它就会保证该component的应用程序进程运行,在需要的时候启动它,并且保证有一个可用的component实例,当需要的时候创建它。
content provider在接收到ContentResolver的请求时被激活。另外的三种component — activity, service和broadcast receiver是被称为intents的异步消息激活的。一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI等等。例如,它可以传递给activity一个请求,让它显示一张图片或者让用户编辑一些文字。对于broadcast receiver来说,Intent对象指定了操作的名称。例如,它可以把“照相机按钮被按下”这个事件告诉感兴趣的应用程序。
激活每一种component有不同的方法:
一个content provider仅当它响应来自ContentResolver的请求时有效。一个broadcast receiver仅当它响应广播消息的时候有效。因此它们不需要显式的关闭。
另一方面,Activity和service可能长期存在。因此android有关闭activity和service的方法:
component也可以在不需要的时候或者内存紧张的时候被系统关闭。在后面的Component Lifcycles一节中会介绍这一点。
在android启动一个应用程序的component之前,它必须知道这个component的存在。因此,应用程序在manifest文件中声明了它的component。manifest文件和代码、资源文件等一起被打包在.apk文件中。
manifest文件是一个结构化的xml文件。任何应用程序中都叫做AndroidManifest.xml。它还有其他一些功能,例如指定应用程序需要连接的库,以及需要的权限。
manifest的主要功能还是告诉android这个应用程序的component,例如一个activity可以像这样定义:
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
</activity>
. . .
</application>
</manifest>
<activity>元素的name属性指定了实现该activity的Activity子类。icon和label属性指向该activity呈现给用户的图标和标签。
其他的component也是用类似的方法来定义 — <service>,<receiver>和<provider>分别定义了service,broadcast receiver和content provider。在manifest中未声明的Activity, service以及content provider对于系统是不可见的,因此永远不会被运行。但是,broadcast receiver可以在manifest中定义,也可以动态的在代码中被创建并是用Context.registerReceiver()来注册到系统中。
关于manifest文件的结构详见The AndroidManifest.xml.
Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。例如:
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
<intent-filter . . . >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter . . . >
<action android:name="com.example.project.BOUNCE" />
<data android:mimeType="image/jpeg" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
. . .
</application>
</manifest>
第一个filter — action "android.intent.action.MAIN"和 category "android.intent.category.LAUNCHER"表示该activity应该是在主程序启动界面中出现的一个程序,用户可以直接在主界面中启动它。
第二个filter声明了一个可以操作某种特定类型数据的action。
一个component可以有任意多数量的intent filter,每一个都声明了不同的能力集合。如果它没有任何filter,那么它只能在显式指定名字的方式下启动。
对于在代码中创建和注册的broadcast receiver,intent filter直接被实例化为一个IntentFilter对象。其他的filter在manifest中设置。
关于Intent Filter 详见单独的文档。
前面提到了,一个activity可以启动另一个activity,包括定义在不同的application中的activity。假设你希望用户显示某个地方的地图。已经有一个activity可以做这件事情,因此你的activity只需要把一个intent object设置好并传递给startActivity()就可以了。地图浏览器会显示地图。当用户按下BACK键,你的activity又会重新显示。
对于用户来说,地图浏览器就好像是你的应用程序中的一部分,即使它是在另一个应用程序中定义并运行的。android将这两个activity放在同一个task中来让用户感觉它们是同一个程序。简单的说,一个task就是用户感觉上的一个application。它是一组相关的activity,组织在一个stack中。我们称开始任务的activity为根activity。一般来说,根activity是用户在程序启动器中启动的。在stack顶端的activity是当前正在运行的activity。当一个activity启动另一个时,新的activity被推入stack并成为运行的activity。前一个activity仍然保存在stack中。当用户按下BACK键时,当前的activity被拖出,前一个activity成为运行activity。
stack储存的是对象,因此如果一个stack包含了同一个Activity类的不同实例,它们会放在不同的地方。stack中的activity只能推入和拖出,而不能进行其它的顺序变化。
A task is a stack of activities, not a class or an element in the manifest file. So there's no way to set values for a task independently of its activities. Values for the task as a whole are set in the root activity. For example, the next section will talk about the "affinity of a task"; that value is read from the affinity set for the task's root activity.
一个task是多个activity构成的stack,而不是在manifest文件中的一个类或者一个元素。因此没有办法来设定一个task的属性而不管它的activity。一个task的所有属性值是在根activity中设定的。例如task的affinity。它是从根activity中读取的。
一个task中所有的activity作一个整体来运动。整个task可以被提到前台或者放到后台。例如,当前的task有4个activity。用户按下HOME键,进入程序启动器,然后选择一个新的应用程序(事实上就是一个新的task).当前的task进入后台,新task的根activity被显示。然后用户又进入主界面启动前一个应用程序,则那个有4个activity的task进入前台。当用户按下BACK键时,不会显示刚才那个task的root activity,而是将当前task的stack顶部activity移除并显示前一个activity。
以上是activity和task的默认行为。但是也有其他的方法来改变这种行为。activity和task之间的联系和行为是由启动activity的intent对象中的标签以及manifest文件中<activity>元素的属性值共同影响的。
主要的Intent标签值有以下几种:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
主要的<activity>属性有:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
下面我们来看看它们的作用。
默认情况下一个应用程序中所有的activity相互之间都有一个affinity. 对于一个activity也可以设置一个单独的affinity. 当启动activity的Intent对象包含FLAG_ACTIVITY_NEW_TASK标志,并且
activity的allowTaskReparenting属性为"true".
FLAG_ACTIVITY_NEW_TASK 标志
一个新的activity在默认情况下在调用startActivity()的activity所属的task中启动,被推入和启动它的activity相同的activity栈中。但是,如果传给startActivity()的Intent对象包含
FLAG_ACTIVITY_NEW_TASK标志,则系统寻找一个不同的task来管理改这个新的activity。一般来说是一个新的task,不过也不一定是。如果已经存在一个和新activity有相同affinity的
task,则该activity在这个task中启动。否则启动一个新的task。
allowTaskReparenting属性
如果一个activity的allowTaskReparenting属性为"true",它可以从它启动时所在的task移动到另一个它具有affinity的task中。例如,假设一个旅游助理软件中有一个activity是用来报告天气的。它和
这个应用程序中的其它activity有相同的affinity(默认affinity)并且允许reparenting。某个activity启动天气预报器,因此它和这个activity属于同一个task。然而,当旅游应用程序进入前台时,天气
报告器会被重新分配到旅游应用程序的task中去。
如果对于一个用户来说,一个apk文件包含了多于一个的应用程序,很可能你需要为不同的activity赋予不同的affinity。
<activity>元素的launchMode属性可以有4种值:
"standard" (the default mode)
"singleTop"
"singleTask"
"singleInstance"
这些模式相互之间的区别有以下4个方面:
当一个已经存在的activity需要处理一个新的intent的时候,这个intent对象被使用onNewIntent()传递到activity中. (开始启动activity的intent对象可以使用getIntent()方法来取得。)
注意当一个新的Activity实例被创建来处理intent的时候,用户总是可以用BACK键来返回到上一个状态(上一个activity)。但当一个已有的Activity实例处理intent的时候,用户不能用BACK键回到之前的状态。关于启动模式详见<activity>元素的文档。
如果用户离开一个task很长时间,系统会将该task除了根activity之外所有的其它activity清除掉。当用户返回到该task,它和用户离开的时候一样,只是只剩下了初始的activity。这里的想法是,在一段时间以后,用户可能丢掉了他们原来想做的事情,并且回到这个task中来做新的事情。这是默认的做法。有一些activity属性可以用来改变这个做法:
alwaysRetainTaskState 属性
如果根activity的该属性为"true",则上述默认行为不会发生。该task将保留所有的activity.
clearTaskOnLaunch 属性
如果根activity的该属性为"true",则只要用户离开就将除根activity之外所有activity清除。
The finishOnTaskLaunch attribute
该属性和clearTaskOnLauch行为类似,但它作用于单个activity,而非整个task。它可以导致包括根activity关闭。当设为"true"时,该activity只在当前会话中属于该task。当用户离开再返回时该activity不再有效。
还有一种方法来强制使activity被从stack上移除。如果intent对象包含FLAG_ACTIVITY_CLEAR_TOP标志,并且目标task已经有一个可以处理该intent的activity,则所有在该activity之上的activity都被清除掉。如果该activity的启动模式为"standard",它也会被从stack上移除,并且启动一个新的实例来处理该intent。这是因为当启动模式为"standard"时,总是会启动一个新的实例来处理Intent。
FLAG_ACTIVITY_CLEAR_TOP常常和 FLAG_ACTIVITY_NEW_TASK一起使用,可以找到另外一个task中的activity并把它放在一个可以响应intent的位置。
当需要一个activity作为整个应用程序的进入点时,我们给它一个intent filter,其中action为 "android.intent.action.MAIN",category为"android.intent.category.LAUNCHER"。这种filter使得一个图标和一个标签显示在程序启动器中,使用户可以启动该task或者返回到该task。
返回该task这种能力时很重要的:用户需要能够离开一个task并且一段时间后能返回。因此,两种永远启动新的task的启动模式"singleTask"和"singleInstance"应该只在具有MAIN和LAUNCHER的filter的activity中使用。设想如果没有该filter的话,一个intent启动了一个"singleTask"的activity,启动了一个新的task,用户在该task中工作了一段时间。用户按下HOME键离开它,该task现在家屏幕后面。由于它不在应用程序启动器中,用户没有办法来返回到它。
FLAG_ACTIVITY_NEW_TASK标签也有一个难题。如果该标签导致一个activity启动一个新的task,然后用户按下HOME键离开,必须有一种方法使得用户可以回到它。有些程序(例如通知管理器)总是在外部task中启动activity,因此它们总是使用FLAG_ACTIVITY_NEW_TASK标志。如果你有一个activity可以被外部程序用这个标签启动,注意要让用户有一个方法来返回原来的位置。
当你不想要用户能够返回到前一个activity时,将<activity>元素的"finishOnTaskLaunch"设为"true"。
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在其他的进程中运行或者在进程中创建其它的线程。
一个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的状态,下一节我们讨论之。
即时你可以将应用程序限制在一个单个进程中,有可能你也需要启动一个线程来做一些后台工作。由于用户界面需要永远快速响应,负责activity的线程不应做耗时多的工作。这些工作应该放在另一个线程中做。
线程使用Java Thread对象在代码中创建。Android提供了一些类来方便管理线程 — Looper用来在线程中运行一个消息循环,Handler用来处理消息,HandlerThread用来在消息循环中设置一个线程。
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建立连接的过程:
在一些情况下,你实现的方法可能被多于一个线程来调用。因此它们必须被写成线程安全的。
这一点对于可以远程调用的方法来说一般都是正确的——就像上一节所说的RPC机制一样。当一个IBinder对象实现的方法在IBinder的同一个进程中调用时,该方法是在调用者的线程中进行的。但是,当该调用在另外一个进程时,该方法是在Android维护的一个位于IBinder进程中的线程池中的一个线程中调用的;它不是在进程的主线程中调用的。例如,一个service的onBind()方法会被该service的进程中的主线程调用,使用onBind()返回的对象实现的方法(例如,一个实现RPC方法的Stub子类)将被从线程池中的线程调用。由于service可以有多于一个的client,多于一个的线程池线程可以同时处理相同的IBinder方法。因此IBinder方法必须被实现为线程安全的。
类似的,一个content provider可以接收另一个进程中的请求。虽然ContentResolver和ContentProvider隐藏了进程间通信的细节,ContentProvider响应请求的方法——query(),insert(),delete(),update()以及getType()——是从content provider进程的线程池中运行的,而不是进程的主线程。由于这些方法可以被任意多线程同时调用,因此它们也需要被实现为线程安全的。
Activity有三种基本状态:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
所有这些方法都可以被重写来做状态改变时应该做的工作。所有的activity必须实现onCreate()方法来做初始化工作。许多activity实现onPause()来确认数据修改并做好停止和用户交互的准备。
这7个方法一起定义了一个activity的生命周期。通过实现这些方法,你可以管理3个嵌套的生命周期循环:
下表阐述了这些循环以及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来节约内存时,用户可能希望当他们返回该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()来完成后者。
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()可以可选的启动它。
和activity一样,service也有生命周期方法。但比较少,并且为public而不是protected:
void onCreate()
void onStart(Intent intent)
void onDestroy()
通过实现这些方法,你可以管理service生命周期的两个循环:
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)
It has a BroadcastReceiver object that's executing its onReceive() method.
他有一个BroadcastReceiver对象正在运行onReceive()方法。
在某个时间,只有少数的前台进程会存在。它们只有在极端情况下被Kill——内存严重不足以至于它们不能都同时运行。一般的,在这个时间,设备达到了一个请求分页的状态,因此需要kill一些 前台进程来是用户界面能够响应。
它持有一个绑定到可见activity的service。
一个可见进程被认为非常重要,只有在需要资源来让所有前台进程运行时才会被Kill掉。
一个后台进程是一个持有一个对用户不可见的activity的进程(Activity的onStop()方法被调用)。这些进程对用户体验没有直接影响,并且可以在任意时间被Kill以保证内存的需要。一般来说有很多后台进程在运行,因此它们被保存在一个LRU列表中来保证最近使用的拥有该activity的进程是最后kill的进程。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,kill该process将不会对用户体验造成不好的影响。