Android 进程和线程

Android 进程和线程

当一个应用程序组件启动和应用程序没有任何其他组件在运行时,Android系统开始一个新的Linux进程执行一个线程应用。 默认情况下,同一个应用程序的所有组件运行在相同的进程和线程里(称为“主”线程)。如果一个应用程序组件启动并且已经存在一个申请的过程(因为另一个组件的应用程序的存在),那么该组件在程序启动并使用相同的执行线程。然而你可以在你的应用程序运行在单独的进程安排不同的组件,您可以创建额外的线程的任何进程。

本文讨论了进程和线程在一个Android应用程序的工作。

Processes 进程

默认情况下,所有的组件相同的应用程序运行在同一进程中,大多数应用程序不应该改变这个。然而,如果你发现你需要控制某个组件所在的进程,你可以在manifest文件中。

Manifest 为每个类型的组件—, , , 和 —支持 android:process 属性,可以指定组件应该运行在的进程。你可以设置这个属性使每个组件运行在自己的进程或使一些组件共享一个进程而别人不。你也可以设置android:process 使不同应用程序的组件运行在同一进程中提供的应用程序共享相同的Linux用户ID和具有相同的签名的证书。

元素也支持android:process属性,去设置应用到所有组件的默认值。

Android可能会决定关闭一个进程在一些点,当内存低,需要的是其他过程更直接的用户服务。应用组件运行的过程中,也因此被杀死。一个过程再次开始为这些组件时,又为他们做的工作。

当决定杀死哪个进程,Android系统衡量他们对用户的重要性。例如,它更容易关闭过程举办活动,不再是在屏幕上可见,相比一个宿主进程可见的活动。决定是否终止一个进程,因此,取决于在进程中运行的组件的状态。使用的规则来决定谁会被终止。

Process lifecycle 进程生命周期

Android系统试图尽可能长时间保持一个应用程序进程,但最终需要删除旧的进程,以回收内存用于新的或更重要的进程的启动。 要确定哪些进程保持和杀死,系统会将每个进程列入一个“优先级层次结构”。 第一消除与最低优先级的进程,然后是下一个最低的优先级,依此类推,直到恢复所需的系统资源。.

有五个级别的优先级。 下面的列表中列出了不同类型的进程的优先级顺序(第一个是最重要的 , 最后被杀死 ):

  • 1.Foreground process 前台进程

    这一进程是用户正在做的前台进程。认为如果下列条件为真:

    • 它承载了一个 Activity,与用户进行交互活动( Activity 的onResume()方法被调用)。
    • 它承载了一个 Service 绑定了该用户的互动与活动。
    • 它承载了一个 Service 运行在前台---—这个service 调用了 startForeground().
    • 它承载了一个 Service 执行了一个生命周期的回调 (onCreate(), onStart(), 或 onDestroy()).
    • 它承载了一个 BroadcastReceiver 执行了他的 onReceive() 方法.
      一般来说,只有仅剩一些前台进程存在的时候。杀死他们只作为最后的手段,如果内存是如此之低,连他们都无法继续运行时。一般来说,在这一点上,该装置已达到一个内存分页状态,因此杀死一些前台进程是为了保持用户界面的响应。
  • 2.Visible process 可见进程

一个过程,没有任何前景的组件,但仍会影响到用户所看到的屏幕上。一个过程被认为是可见,如果满足下列条件:

  • 它承载了一个 Activity 不在前台,但仍然对用户可见的(其onPause()方法被调用) 这可能发生,例如,如果前台活动开始了对话,这允许先前的活动可以看到后面。

  • 它承载了一个 Service 绑定到一个可见的(或前景) activity.
    一个可见进程被认为非常重要,如果杀死他们,一定是为了保持所有前台进程运行。

  • 3.Service process 服务进程

这一进程运行的service ,是那些已执行startService() 方法且不属于前面两个高类别的服务。虽然服务流程不是所有用户可见的,但他们所做的事是用户关心的(如播放背景音乐或下载数据在网络上),所以系统会保持运行,除非没有足够的内存来保持他们在所有的前台和可见的进程。

  • 4.Background process 后台进程

一个进程开启过activity ,但是当前用户不可见(活动的onStop()方法被调用)。这些进程对用户的体验没有直接的影响,并且该系统可以随时杀死他们回收前台,可见的内存,或服务进程。通常有许多后台进程在运行,所以他们被保存在一个LRU(最近最少使用)列表以确保与活动,最近被用户看到的进程是被最后杀死的。如果一个活动实现其生命周期方法正确,并保存其当前状态,杀死它的进程将不会对用户体验产生可见的效果,因为当用户导航回到活动,活动恢复它的所有可见的状态。看Activities文档信息的保存和恢复状态。

  • 5.Empty process 空进程

一个进程,不举行任何活动的应用程序组件。保留这种进程的唯一原因是缓存的目的,提高组件的启动时间需要运行在它的下一次。系统常常杀死这些进程来平衡整个系统的资源过程缓存和底层内核缓存之间。

一个进程可以有较高级别的Android的优先级,基于它的重要性。例如,如果一个进程开启了 一个service 和一个可见的activity,这个进程的将作为一个可见的过程,不是一个服务过程。

此外,一个进程的排名可能会增加,因为其他的流程都依赖于它的一个过程,是为另一个进程永远不能被排名低于这个过程中,服务。 例如,如果一个内容提供商过程中的服务进程B中的客户端或服务过程中,如果A是必然进程B中的一个组件,进程A总是被认为至少是同样重要进程B

因为一个进程运行服务的过程与背景活动,发起一项活动,可能会做一个长期运行的操作,操作以及启动服务 ,而不是简单地创建一个工作线程,特别是如果操作将可能高于排名经久活动。 例如,一个活动的图片上传到一个网站,应该启动一个服务执行上传,因此可以继续在后台上传,即使用户离开活动。 使用服务保证该操作将至少有“服务进程”的优先级,不管发生了什么活动。 广播接收机应采用服务,而不是简单地把在一个线程中耗时的操作,这是一样的道理。

Threads 线程

当一个应用程序启动时,系统会创建一个线程执行的应用,称为“主”。 这个线程是很重要的,因为它是在事件调度到相应的用户界面部件,包括绘图事件负责。 它也是你的应用程序从Android的UI工具包的android.widget和android.view封装的组件与组件的线程。 因此,主线程有时也称为UI线程。

系统不会为每一个组件实例创建单独的线程。 所有在同一个进程中运行的组件在UI线程中实例化,并从该线程调度系统每个组件的调​​用。 因此,方法,应对系统的回调(如onKeyDown()报告用户操作或生命周期回调方法)总是运行在UI线程中的过程。

例如,当用户触摸屏幕上的一个按钮,您的应用程序的UI线程分发触摸事件到窗口,这反过来又将其压状态和发送一个无效的请求事件队列。UI线程取出请求和通知部件应该重绘自己。

当你的应用程序执行密集的响应用户的交互,单线程模型可能产生性能差,除非你恰当的实现你的应用。特别是,如果所有的事情都是发生在UI线程,执行如网络接入或数据库查询将会阻塞整个UI长操作。当线程被阻塞,没有事件可以被分发,包括绘制事件。从用户的角度出发,应用假死。更糟糕的是,如果UI线程被阻塞超过几秒(约5秒目前)用户与臭名昭著的“应用程序没有响应”(ANR)对话框。用户可能决定退出你的应用程序和卸载它,如果他们不高兴。

此外,Andoid UI工具包不是线程安全的。所以,你不能从一个工作者线程,你必须做的所有操作用户界面的UI线程处理你的UI。因此,只是有两个规则对Android系统的单线程模型:

  • 不要阻塞UI线程
  • 不能从UI线程外部访问Android UI工具包

工作线程

由于上述单线程模型,它的应用程序的UI的响应至关重要,你不要阻塞UI线程。如果你已经执行的操作,是不是瞬时的,你应该确保在单独的线程做(“后台”或“工作”的线程)。

例如,下面是一些代码,点击监听器下载图像从一个单独的线程,并显示在一个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线程之外这样访问Android UI工具包修改ImageView而非UI线程的线程。这可能会导致未定义的和意外的行为,这可能是困难和追踪耗时。

要解决此问题,Android提供了几种不同的方式从其他线程访问UI线程。这里是一个列表的方法,可以帮助:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

例如,你可以通过使用视图解决上述代码后(运行)的方法:

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线程。

然而,由于操作的复杂性增加,这种代码会变得复杂和难以维护。与一个工作者线程处理更复杂的交互,你可以考虑使用一个处理程序在你的线程,处理来自UI线程的消息。也许最好的解决方案,但是,是扩展AsyncTask,简化了工作线程的任务,需要与用户界面交互执行。

使用AsyncTask

AsyncTask允许你在你的用户界面执行异步工作。它在工作线程中执行阻塞操作,然后公布在UI线程上的结果,而不需要你去处理线程和/或处理自己。

使用它,你必须扩展AsyncTask并且实现doinbackground()回调方法,它运行在后台线程池。更新你的UI,你应该实现onpostexecute(),提供从doinbackground()结果和运行在UI线程,因此你可以安全地更新UI。然后你可以通过从UI线程调用execute()运行任务。

例如,你可以使用AsyncTask这样实施以前的例子:

public void onClick(View v) {

    new DownloadImageTask().execute("http://example.com/image.png");

}



private class DownloadImageTask extends AsyncTask {

    /** 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);

    }

}

进程间通信

Android提供了一个用于进程间通信(IPC)机制,使用远程过程调用(RPC)方法被称为一个活动或其他应用程序组件,但远程执行(在另一个进程中),返回给调用者返回任何结果。 这需要一个方法调用和它的数据分解到一个水平,操作系统可以理解的,传送过程和从本地到远程进程和地址空间的地址空间,然后重新组装,重演呼叫。 返回值,然后在相反的方向传送。 Android提供了所有的代码来执行这些IPC交易,这样你就可以专注于定义和执行RPC编程接口。

  • android中线程与线程,进程与进程之间如何通信1、一个 Android 程序开始运行时,会单独启动一个Process。
    默认情况下,所有这个程序中的Activity或者Service都会跑在这个Process。
    默认情况下,一个Android程序也只有一个Process,但一个Process下却可以有许多个Thread。
  • 一个 Android 程序开始运行时,就有一个主线程Main Thread被创建。该线程主要负责UI界面的显示、更新和控件交互,所以又叫UI Thread。
    一 个Android程序创建之初,一个Process呈现的是单线程模型--即Main Thread,所有的任务都在一个线程中运行。所 以,Main Thread所调用的每一个函数,其耗时应该越短越好。而对于比较费时的工作,应该设法交给子线程去做,以避免阻塞主线程(主线程被阻塞, 会导致程序假死 现象)。
  • Android单线程模型:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。如果在子线程中直接修改UI,会导致异常。

你可能感兴趣的:(Android 进程和线程)