Android进程详解


当一个应用启动的时候,如果这个应用没有其它组件已经在运行了,那么系统就会为这个应用启动一个新的Linux进程,这个进程只有一个线程,即我们熟知的main线程。默认情况下,一个应用的所有组件都运行在一个进程和线程(main)中。这点从Logcat的打印信息可以看出,Logcat视图中的Application那一栏,打印的是当前应用的进程的name值,而通常情况下是打印出的是manifes的package的值,这是因为我们的Application的标签没有设置progress的值,如果没有设置的话,系统默认使用package的值来作为当前应用的进程的名字。当然,你完全可以安排不同的组件运行于不同的进程中,并且你可以为任何程序创建另外的线程,这点我们在做异步操作更新界面的时候,如果使用Handler的方式的话,往往会新创建一个线程。如:

new Thread()

{

public void run()

{

…………………………………………..

mHandler.sendEmptyMessage(0);

}

}.start();

下面说一下,如何实现同一个应用的不同组件运行在不同的进程中:
默认下,同一个应用的所有组件都运行在同一个进程中并且大多数程序不必改变这种情况,如果你非要同一个应用的不同组件运行在不同的进程中,也可以通过manifest文件实现。

Manifest文件中的所有支持android:process属性的那些项(<activity>,<service>,<receiver>,和<provider>)都可以指定一个进程,设置该属性之后的组件将在该属性所对应的进程中运行。你可以设置这个属性使每个组件运行于其自己的进程或只是其中一些组件共享一个进程,你也可以设置android:process以使不同应用的组件可以运行于同一个进程。<application>元素也支持android:process属性,用于为所有的组件指定一个默认值。Android可能在某些时刻决定关闭一个进程,比如在内存不足的时候,系统会自动关闭一些其他应用的后台进程,以保持当前正在运行的进程的运行。

进程的生命周期:Android系统会尽量维持一个进程的生命,直到最终需要为新的更重要的进程腾出内存空间。为了决定哪个该杀哪个该留,系统会根据运行于进程内的组件和组件的状态把进程置于不同的重要性等级。当需要系统资源时,重要性等级越低的先被淘汰。Android重要性等级被分为5个等级(从高到低):(1)前台进程(2)可见进程(3)服务进程(4)后台进程(5)空进程.

进程的优先级:

当系统的内存不足时,android系统将根据进程优先级选择杀死一些不太重要的进程。进程优先级从高到低分别为:

1、  前台进程,以下进程为前台进程:
(1)进程中包含处于前台的正与用户交互的activity;
(2)进程中包含与前台activity绑定的service
(3)进程中包含了调用了startForeground()方法的service
(4)进程中包含正在执行onCreate(),onStart(),或onDestroy()方法的service
(5)进程中包含正在执行onReceive()方法的BroadcastReceiver

系统中前台进程的数量很少,前台进程几乎不会被杀死,只有当内存低到无法保证所有的前台进程同时运行时才会选择杀死某个前台进程。

2、  可见进程,以下进程为可见进程:
(1)进程中包含未处于前台但仍然可见的activity(调用了activity的onPause()方法),典型的情况是运行activity时弹出对话框,此时的activity虽然不是前台activity,但是其仍然可见。
(2)进程中包含于可见activity绑定的service

可视进程不会被系统杀死,除非为了保证前台进程的运行而不得已为之。

3、  服务进程:进程中包含已启动的service

4、  后台进程:进程中包含不可见的activity(onStop()方法调用后的activity)。后台进程不会直接影响用户体验,为了保证前台进程/可视进程/服务进程的运行,系统随时都有可能杀死一个后台进程。一个正确的实现了生命周期方法的activity处于后台时被系统杀死,可以在用户重新启动它时恢复之前的运行状态。

5、  空进程:不包含任何处于活动状态的进程是一个空进程,系统经常杀死空进程,这不会造成任何影响。空进程存在的唯一理由是为了缓存一些启动数据。

讲到这里理论部分已经讲完了,现在咱们通过一个Demo来加深一下理解。

首先看一下测试Demo的Manifest文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gc.testprogressdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
	<!-- android:process="newpackage.test"  设定此Demo的进程名字为newpackage.test,即此Demo所有
		组件默认都运行在该进程中
	 -->
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:process="newpackage.test"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--  android:process="NewProgress."  将NewProgress组件运行在NewProgress.进程里。
        	注意:android:process的值的格式须为:xxx.xxxx。这个必须含有一个“.”,否则编译通不过。
        	测试编译环境为5.0
        -->
        <activity
            android:name=".NewProgress"
            android:label="@string/app_name" 
            android:process="NewProgress."
            />
        <activity
            android:name=".NowProgress"
            android:label="@string/app_name" 
            
            />
    </application>

</manifest>

大家都过上面代码可以看到,此Demo是运行在进程newpackage.test里的,NewProgress这个Activity是运行在NewProgress.这个进程里的,下面大家先看一下运行效果图,如下图所示:


下面给出获取当前进程的名字的代码,如下:

package com.gc.testprogressdemo.uitls;

import android.app.ActivityManager;
import android.content.Context;
/**
 * 返回当前进程的名字
 * @author Android将军
 *
 */
public class GetProgressName {

	public static String getCurrentProgressName(Context context)
	{
		int pid=android.os.Process.myPid();
		ActivityManager mActivityManager=(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
		for(ActivityManager.RunningAppProcessInfo appProcess:mActivityManager.getRunningAppProcesses())
		{
			if(appProcess.pid==pid)
			{
				return appProcess.processName;
			}
		}
		return null;
		
	}
}

由于此Demo比较简单,故不在过多的阐述,文章末尾会附上Demo的下载地址。

至于如何判断当前进程是哪一个级别的进程,可以将上面的函数返回代码修改为

return appProcess.processName+"级别"+appProcess.importance;

其中importance是反应进程优先级的属性,具体请查看下表:


在实际开发中,如果大家想获得进程的状态可以通过查看你想知道的进程的importance属性。

在此我在Demo中重写了MainActivity与NewProgress的生命周期方法,Logcat的打印日志如下:

12-10 13:05:13.083: I/System.out(1452): MainActivity所在进程onCreate:newpackage.test级别100               前台进程
12-10 13:05:13.091: I/System.out(1452): MainActivity所在进程onStart:newpackage.test级别100                  前台进程
12-10 13:05:13.095: I/System.out(1452): MainActivity所在进程onResume:newpackage.test级别100            前台进程
12-10 13:06:30.335: I/System.out(1452): MainActivity所在进程onPause:newpackage.test级别100                前台进程
12-10 13:06:30.595: I/System.out(1471): NewProgress所在进程onCreate:NewProgress.级别100              前台进程
12-10 13:06:30.595: I/System.out(1471): NewProgress所在进程onStart:NewProgress.级别100                 前台进程
12-10 13:06:30.599: I/System.out(1471): NewProgress所在进程onResume:NewProgress.级别100           前台进程
12-10 13:06:30.923: I/System.out(1452): MainActivity所在进程onStop:newpackage.test级别130                可见进程(经典场景:Activity弹出对话框)
12-10 13:07:46.199: I/System.out(1471): NewProgress所在进程onPause:NewProgress.级别100             前台进程
12-10 13:07:46.207: I/System.out(1452): MainActivity所在进程onRestart:newpackage.test级别100             前台进程
12-10 13:07:46.211: I/System.out(1452): MainActivity所在进程onStart:newpackage.test级别100                  前台进程
12-10 13:07:46.211: I/System.out(1452): MainActivity所在进程onResume:newpackage.test级别100          前台进程
12-10 13:07:46.647: I/System.out(1471): NewProgress所在进程onStop:NewProgress.级别400                后台进程
12-10 13:07:46.647: I/System.out(1471): NewProgress所在进程onDestroy:NewProgress.级别400             后台进程



要讲的就这么多,如果大家有什么不明白的可以回复提问,如果有不对之处,也请大家指出。

Demo下载地址:http://download.csdn.net/detail/gc_gongchao/8245593

转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/41851139


Logo

更多推荐