一. 进程生命周期" />
当前位置: 代码迷 >> Android >> 一. 进程生命周期
  详细解决方案

一. 进程生命周期

热度:25   发布时间:2016-05-01 14:25:48.0
Android进程和线程

(译自Android SDK文档Processes and Threads, 不全)

一. 进程生命周期

?

There?are?five?levels?in?the?importance?hierarchy.?The?following?list?presents?the?different?types?of?processes?in?order?of?importance?(the?first?process?is?most?important?and?is?killed?last):

importance?hierarchy.分为五个等级,最重要的进程最后被杀死。

1.?Foreground?progress前台进程

前台进程是用户完成当前任务必需的进程。满足以下条件之一的进程为前台进程:

Hosts用户正在与之进行交互的Activity

1)Hosts被用户正在与之进行交互的Activity绑定的Service

2)Hosts前台Service

3)Hosts正在执行onCreate()onStart()onDestroy()Service

4)Hosts正在执行onReceive()方法的BroadcastReceiver

通常情况下任意时刻仅有少量前台进程。前台进程仅在极端情况下才会被杀死,比如设备内存过低需要进行页面置换。

2.?Visible?progress可见进程

没有前台组件、但仍影响用户屏幕显示内容的进程即为可见进程。

1)Hosts?Visible?Activity,即不在前台、但仍然可见的Activity(已调用onPause())。比如某个原本处于前台的Activity弹出一个对话框,则这个Activity现在处于可见状态

2)?HostsVisible?Activity绑定的Service

可见进程非常重要,除非要保证前台进程运行,一般不会杀死可见进程

3.?Service?progress服务进程

通过startService()方法启动服务的?、且不属于以上两种情况的进程,归为服务进程。服务进程不直接跟用户所见产生关系,但它们通常执行一些用户非常关心的操作,比如在后台播放音乐或下载文件。

4.?Background?progress后台进程

Hosts对用户不可见的Activity(已调用onStop()方法)的进程为后台进程。这些进程不会对用户体验产生直接影响,所以系统可以在任何时候杀死它们以便为前台进程、可见进程、服务进程回收内存。通常同时存在许多后台进程,它们被保存在LRU(least?recently?used)队列中,以保证用户最近使用的Activity最后被杀死。如果一个Activity正确地实现了其生命周期方法,并且保存了当前状态,杀死该进程不会对用户体验产生明显影响。

5.?空进程

不持有任何应用组件的进程为空进程。空进程存在的意义是缓存,以加速下次组件的启动速度。

?

Android尽可能将一个进程往高级别排列。比如,某个进程hosts一个service和一个可见activity,则认为这个进程是可见进程而非服务进程。另外,一个进程的等级也可能因依赖关系而发生变化。一个进程为另一个进程提供服务,则前者等级绝对不可能比后者低。比如,A进程中的?一个content?providerB进程中的一个客户提供服务,或者A进程中的一个serviceB进程中的某个组件绑定,则A进程至少与B进程有同样的优先等级。

?

由于运行service的进程级别比运行后台activity的进程级别高,发起长时间任务(long-running?operation)activity最好通过服务来完成任务,而不是简单地创建一个工作线程,尤其当任务持续时间长过activity自身生命时。比如,一个activity上传图片到网站上,则该activity应当启动一个服务来完成上传操作,当用户离开这个activity时上传工作仍能继续。使用service能保证至少具有service?progress优先级,不管这时activity状态如何。基于同样的理由,broadcast?receiver也应当利用service而非创建线程来完成耗时操作。

?


二. 工作线程

程序启动时,系统创建一个main线程用户执行程序。Main线程非常重要,它负责分发事件到相应的UI部件,包括绘图事件(drawing?events)Main线程有时也称作UI线程。

?

系统并不为每个组件实例创建单独的线程。进程中所有的组件都在UI线程中实例化,对每个组件的系统调用也都从该线程分发。结果,类似于onKeyDown()这样的系统调用都在这个进程的UI线程中运行。

?

单线程应用程序性能低下。如果所有的操作都在UI线程中进行,类似网络访问或数据库访问之类的耗时操作将会阻塞UI。当UI线程被阻塞,事件不能被分发和处理,包括drawing?events。从用户角度,应用死掉了。更糟糕的是,当UI线程阻塞超过5秒钟将会提示ANR

?

此外,UI?toolkit并非线程安全。所以不能在UI线程以外的其他线程操作UI组件。综上所述,归纳出以下两个简单规则:

1.?不要阻塞UI线程

2.?不要在UI线程以外的线程访问和操作UI组件

来看这段代码,它是一个click?listener,用于启动一个线程下载图片并在一个ImageView中展示这个图片:

?

public void onClick(View v) {    new Thread(new Runnable() {        public void run() {            Bitmap b = loadImageFromNetwork("http://example.com/image.png");            mImageView.setImageBitmap(b);        }    }).start();}

?一开始,代码看似一切正常。但仔细就会发现,它违反了以上第2条规则:不要从UI线程以外的其他线程访问和操作UI。以上代码会导致未定义和不可预料的程序行为,这种行为难以跟踪和分析。

?

为了解决这个问题,Android提供了几种方法以便能够从其他线程访问UI线程。方法如下:

1.?Activity.runOnUiThread(Runnable)

2.?View.post(Runnable)

3.?View.post(Runnable,?long?)

所以,可以用第1种方法将代码改成下面这样

?

public void onClick(View v) {    new Thread(new Runnable() {        public void run() {            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");            mImageView.post(new Runnable() {                public void run() {                    mImageView.setImageBitmap(bitmap);                }            });        }    }).start();}
?

?

?

现在的实现是线程安全的了:网络操作在一个单独的线程中完全,而且UI操作也是在UI线程中完成。但问题又来了,当操作变得复杂时,类似的代码会越趋复杂并且难以维护。为了能够在工作线程中完成更加复杂的操作,可以考虑在工作线程中使用Handler来处理来自UI线程的消息。有可能最好的解决方案是继承AsyncTask类,它可以简化需要与UI交互的工作线程。

AsyncTask允许你在UI上执行异步操作。它在工作线程中完成可能产生阻塞的操作,然后在UI线程中发布执行结果,不用自己编码操作线程或Handler。使用AsyncTask时,必须继承AsyncTask并且实现doInBackground()回调方法,这个方法在一个后台线程池中运行。为了能够更新UI,还必须实现onPostExecute(),该方法在UI线程中运行、并且能接收和处理doInBackground()的执行结果。这样,就能安全地更新UI了。

下面是使用AsyncTask来解决前面相同的问题。

?

public void onClick(View v) {    new DownloadImageTask().execute("http://example.com/image.png");}private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {    /** The system calls this to perform work in a worker thread and      * delivers it the parameters given to AsyncTask.execute() */    protected Bitmap doInBackground(String... urls) {        return loadImageFromNetwork(urls[0]);    }        /** The system calls this to perform work in the UI thread and delivers      * the result from doInBackground() */    protected void onPostExecute(Bitmap result) {        mImageView.setImageBitmap(result);    }}
?

?

?

?

  相关解决方案