码迷,mamicode.com
首页 > 其他好文 > 详细

Process And Thread

时间:2016-04-22 20:54:23      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:

当一个应用组件开启,并且这个应用没有其他任何组件运行,安卓系统为这个程序启动一个新的Linux进程,用单个线程进行。默认,同一个应用的所有组件在同一个进程和线程(叫做主线程)中。如果一个应用组件开启,并且这个应用已经有一个存在进程(因为这个程序的另一个组件存在),然后这个组件被在那个进程中启动并且使用同一线程执行。然后,我们可以安排程序中的不同组件在独立的进程中运行,并且我们可以为任何进程创建额外的线程。

这个文档讨论进程和线程如何在安卓应用中工作。

Processes


默认,同一个应用的所有组件在同一个进程运行,并且大多数应用不应该改变这个。然而,如果我们发现我们需要控制一个特定组件属于某个进程,我们可以在manifest文件中这么做。

每一种组件元素(<activity>, <service>, <receiver>, and <provider>)的manifest条目,支持一个android:process属性,这个元素指定那个组件应该运行的一个进程。我们可以设置这个属性,这样每一个组件在它自己的进程中运行或者一些组件分享一个进程而另一些则不。我们也可以设置android:process属性,这样不同应用的组件在同一个进程运行,条件是这些程序分享同一个Linux user ID并且使用同一个证书署名。

这个<application>元素也支持一个android:process属性,设置一个默认值应用到所有组件。

安卓可能决定在某一时刻关闭一个进程,当内存低和被其他进程要求要立刻服务用户。应用组件运行在被杀死的进程也因此被销毁。一个进程为这些组件重新启动当重新有工作要他们去做。

当决定哪个进程要被杀死,安卓系统衡量他们对用户的相对重要性。举例,更乐意杀死一个持有在屏幕不可见的活动的进程,和持有可见活动的进程相比。决定是否停止一个进程,因此,取决于运行在那个进程的组件的状态。决定哪个进程被杀死的规则会在下面讨论。

Process lifecycle

安卓系统尝试尽量长的维护一个应用进程,但是最终需要移除旧的进程为新的或者更重要的进程重新获取内存。为了决定哪个进程保持哪个进程被杀死,系统把每个进程放置在一个“importance hierarchy”,以运行在这个进程的组件和这些组件的状态为基础。最不重要的进程首先被消除,然后是次不重要的,以此类推,随恢复系统资源的需要。

在重要性层级有五个级别。下面展示了按重要性排序的进程(第一个最重要,最后被杀死)。

  1. Foreground process

用户当前正在做的要求的一个进程。一个进程被认为在前台如果任何下面的条件是true:

l  它持有一个用户正在交互的活动(活动的onResume方法被调用)

l  它持有一个服务,这个服务绑定到用户正在交互的活动

l  它持有一个服务,服务在前端运行,服务已经被startForeground调用

l  它持有一个服务,服务正在执行其中一个生命回调(onCreate,onStart,onDestroy)

l  他持有一个BroadcastReceiver,这个广播接收器在执行他的onReceive方法

通常,只有少数前台进程存在任何时间。他们被杀死时只能作为最后的手段,如果内存太低以至于不能继续运行。通常,在这种情况下,设置已经到达了一个内存分页状态,所以为了保持用户界面响应,杀死一些前台进程是必须的。

2.Visible process  
     一个进程没有任何前台组件,但是仍然可以影响用户在屏幕上看到的。一个进程被视为可见的如果下面任何一个为true:

  • 它持有一个不在前台的活动,但是但是活动仍然可见(onPause方法被调用)。这个可能发生,举例,如果前台活动启动一个对话框,对话框允许前一个活动在他后面可见
  • 它持有一个服务,这个服务绑定到一个可见的(或者前台)活动。

一个可见的进程被认为非常重要,不会被杀死,除非这样做是为了保持所有的前台进程运行。

3.Service process 绑定startService启动的服务

    一个运行了使用startService方法启动的服务的进程,并且不会进入上面两个高级类别。虽然服务进程不直接绑定到用户看到的任何东西,他们通常在做用户关心的事情(比如在后台播放音乐或者从网络下载数据),所以系统保持他们运行除非没有足够的内存去保持他们和所有的前台于可见进程一起。

4. Backgroundprocess

一个进程持有一个活动,这个活动当前对用户不可见(活动的onStop被调用)。这些进程对用户体验没有直接影响,系统可以在任何需要为前台,可见或者服务进程获取内存的时候杀死他们。通常有许多后台进程运行,所以他们被保持在一个LRU(least recently used)list去保证有最新被用户看到活动的进程最后被杀死。如果一个活动正确实现它的生命周期方法,并且保存它的当前状态,杀死他的进程不会对用户体验有可见的影响,因为当用户导航返回到这个活动,活动还原所有他的可见状态。(活动文档中关于保存信息的描述,)

5.Empty process

    一个没有持有任何应用组件的进程。唯一保持这个进程的原因是缓存,提高一个组件下次启动的开启时间。系统经常杀死这样的进程为了在进程缓存和底层内核缓存平衡所有系统资源。

 

安卓排名一个进程以它能达到的最高级别,基于当前内部活跃的组件的重要性。举例,如果一个进程持有一个服务和一个可见的活动,这个进程被排位一个可见的进程,而不是一个服务进程。

此外,一个进程的排名可能上升因为其他进程依赖于他。一个服务于另一个进程的进程决不能被排名低于它服务的进程。举例,如果一个内容提供器在进程A服务于一个进程B的客户端,或者一个A中的服务被绑定到进程B中的一个组件,进程A总是被认为至少和B一样重要。

因为执行服务的进程比执行后台活动的进程级别高,一个活动要开始一个耗时操作可能更好去开始一个服务为这个操作,而不是简单创建一个工作线程,尤其当这个操作更可能比活动活的长久。举例,如果一个活动上传图片到一个网站,应该开启一个服务去执行这个上传,这样上传可以在后台执行即使用户离开这个活动。使用服务保证操作至少有“服务进程”优先级,不管活动发生了什么。同样的原因,广播接收器应该使用服务而不是简单的把耗时操作放在一个线程。

 

Threads


当一个应用启动,系统为这个应用创建一个执行线程,叫做主线程。这个线程很重要,因为它复制分配事件到合适的用户界面组件,包括绘图事件。它也是我们应用和来自安卓UI工具包(组件从android.widget和android.view包)的组件交互的地方。因此,主线程有时也被叫做UI进程。

系统不会为每一个组件的实例创建一个独立的线程。所有运行在同一个进程的组件在UI进程实例化,并且系统对每个组件的调用从那个线程发出。因此,响应系统回调的方法(比如onKeyDown报告用户动作或者一个生命回调方法)总是运行中UI进程的线程(run in the UI thread of the process)。

当我们的程序执行集中工作响应用户交互,这个单线程模型可能发生可怜的执行除非我们合适地实现我们的应用。特别的,如果所有的事情发生在UI线程中,执行耗时操作比如网络访问或者数据库查询会阻塞整个UI。当这个进程阻塞,没有事件能够被分发,包括绘图事件。从用户的角度,应用好像停止了。更糟的是,如果UI进程阻塞超过几秒(现在差不多5秒),用户会被呈现声名狼藉的"application not responding" (ANR)对话框。用户可能会决定退出我们的应用,并且如果不开心就卸载。

此外,安卓UI工具包不是线程安全的,所以我们决不能在一个工作线程操作我们的UI。我们必须从UI线程做所有用户界面的操作。因此,对安卓的单进程模型有两个简单的原则:

·        不要阻塞UI进程

·        不要从UI进程之外访问安卓UI工具包

  1. Do not block the UI thread
  2. Do not access the Android UI toolkit from outside the UI thread

Worker threads

因为上文讨论的单进程模型,对于我们应用的UI的响应能力至关重要的是不能阻塞UI进程。如果我们有操作执行不是瞬间的,应该确保在独立的进程执行他们(“background”或者“worker”进程)。

举例,下面是一个点击监听的片段,从一个分离的进程下载图片,在一个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();
}

最初,这个看起来工作良好,因为它创建了一个新进程去处理网络操作。然而,它违反了单线程模型的第二个原则:不要从UI进程之外访问安卓UI工具包。这个例子从工作线程修改ImageView而不是UI进程,这个会导致不明确的和意想不到的行为,这个行为可能很难或者花费大量时间去找出。

为了解决这个问题,安卓提供了几种方法从其他进程访问UI进程。下面是可能有帮助的方法:

举例,可以使用 View.post(Runnable) 方法修复上面代码:

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();
}

现在这个实现是线程安全的:网络访问在分离的进程同时ImageView在UI进程中操作。

然而,随着操作的复杂性提升,这种代码可能变得复杂并且很难维护。为了处理和工作进程更复杂的交互,我们可能考虑在我们工作进程使用Handler,去执行消息传送从UI进程。可能最好的方法,然而,是实现AsyncTask类,这个类简化了需要和UI交互的工作进程的任务的执行。

Process And Thread

标签:

原文地址:http://blog.csdn.net/qingziguanjun1/article/details/51202693

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!