转自:http://blog.csdn.net/yihongyuelan/article/details/7215990


本文将通过三大部分来讲解Android中程序与Service的交互方式,这里说的交互方式指的是如何与Service进行消息的传递,比如:从Service中获取信息,向Service发送信息等等。举个简单的例子,当我们通过手中的Android设备在网络上下载电影的时候,我们需要使用Service实现在后台下载,但同时将下载进度通过当前的Activity来展示给用户,那么我们就需要和Service有一个实时交互的动作。

文章分为:综述、五种交互方式的讲解、总结这三部分。在第二部分中列出了五种交互方式,分别是:通过广播交互、通过共享文件交互、通过Messenger(信使)交互、通过自定义接口交互、通过AIDL交互。

什么是Service?

Service翻译过来就是服务的意思,当我们的应用程序需要做一个长耗时的操作,还有可能需要和别的程序交互的时候,我们就需要使用Service。

1. Service不是一个单独的进程,除非单独声明,否则它不会运行在单独的进程中,而是和启动它的程序运行在同一个进程中。

2. Service不是线程,这意味著它将在主线程里运行。

也就是说Service既不是进程也不是线程,它们之间的关系如下:


可能有的朋友会问了,既然是长耗时的操作,那么Thread也可以完成啊。没错,在程序里面很多耗时工作我们也可以通过Thread来完成,那么还需要Service干嘛呢。接下来就为大家解释以下Service和Thread的区别。

首先要说明的是,进程是系统最小资源分配单位,而线程是则是最小的执行单位,线程需要的资源通过它所在的进程获取。

Service与Thread的区别:

Thread:Thread 是程序执行的最小单元,可以用 Thread 来执行一些异步的操作。

Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。

Thread 的运行是独立的,也就是说当一个 Activity 被 finish 之后,如果没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,不再持有该 Thread 的引用,也就是不能再控制该Thread。另一方面,没有办法在不同的 Activity 中对同一 Thread 进行控制。
例如:如果 一个Thread 需要每隔一段时间连接服务器校验数据,该Thread需要在后台一直运行。这时候如果创建该Thread的Activity被结束了而该Thread没有停止,那么将没有办法再控制该Thread,除非kill掉该程序的进程。这时候如果创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一个Service,而系统也只会创建一个对应 Service 的实例)。
因此可以把 Service 想象成一种消息服务,可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService、Context.unbindService来控制它,也可以在 Service 里注册 BroadcastReceiver,通过发送 broadcast 来达到控制的目的,这些都是 Thread 做不到的。

启动service有两种方法:
1. Context.startService()
调用者(Client)与服务端(Server)之间没有关联,即使调用者退出,服务仍可运行。
2. Context.bindService()
调用者(Client)与服务端(Server)绑定在一起,可以多个调用者(Client)绑定一个服务端(Server),当所有的调用者(Client)退出,服务端(Server)也就终止。

Service的生命周期:

1. 被启动的服务(startService())的生命周期。
如果一个Service被某个Activity 调用Context.startService() 方法启动,那么不管是否有Activity使用bindService()绑定或unbindService()解除绑定到该Service,该Service都在后台运行。如果一个Service被多次执行startService(),它的onCreate()方法只会调用一次,也就是说该Service只会创建一个实例,而它的onStartCommand()将会被调用多次(对应调用startService()的次数)。该Service将会一直在后台运行,直到被调用stopService(),或自身的stopSelf方法。当然如果系统资源不足,系统也可能结束服务。
2. 被绑定的服务(bindService())的生命周期。
如果一个Service被调用 Context.bindService ()方法绑定启动,不管调用bindService()调用几次,onCreate()方法都只会调用一次,而onStartCommand()方法始终不会被调用,这时会调用onBind()方法。当连接建立之后,Service将会一直运行,除非调用Context.unbindService() 断开连接或者之前调用bindService() 的 Context 不存在了(如该Activity被finish),系统将会自动停止Service,对应onDestroy()将被调用。
3. 被启动又被绑定的服务的生命周期。
如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。调用unbindService()将不会停止Service,而必须调用stopService()或Service的stopSelf()方法来停止服务。
4. 当服务被停止时清除服务。
当一个Service被终止时,Service的onDestroy()方法将会被调用,在这里应当做一些清除工作,如停止在Service中创建并运行的线程等。

Process的生命周期:

当Service运行在低内存的环境时,系统会kill掉一些进程。因此进程的优先级将会狠重要:
1. 如果Service当前正在执行onCreate()、onStartCommand()、onDestroy()方法,那麼此时主进程将会成为前台进程来保证代码可以执行完成而避免被kill。
2. 如果Service已经启动,那么主进程将会比其他可见的进程的重要性低,但比其他看不见的进程高。这裡说的可见指的是对用户来讲,可见的进程优先级永远是最高的,用户至上嘛。但只有少部分进程始终是用户可见的,因此除非系统处於极度低内存的时候,不然 service是不会被kill的。
3. 如果有Client端连到Service,那么Service永远比Client端重要。
4. Service可以使用startForeground()将Service放到前台状态。这样在低内存时被kill的几率更低,但如果在极低内存的情况下,该Service理论上还是会被kill掉。但这个情况基本不用考虑。

以上文章将要涉及到的知识进行了初步讲解,包括Service的基础知识以及为什么要用Service,后续文章将探讨与Service交互的几种方式。



进程与生命周期

Android系统会尽可能长的延续一个应用程序进程,但在内存过低的时候,仍然会不可避免需要移除旧的进程。为决定保留或移除一个进程,Android将每个进程都放入一个重要性层次中,依据则是它其中运行着的组件及其状态。重要性最低的进程首先被消灭,然后是较低的,依此类推。重要性共分五层,依据重要性列表如下:

1.前台进程是用户操作所必须的。当满足如下任一条件时,进程被认为是处于前台的:

o它运行着正在与用户交互的activityActivity对象的onResume()方法已被调用)。

o一个正在与用户交互的activity使用着它提供的一个服务。

o它包含着一个正在执行生命周期回调方法(onCreate()onStart()onDestroy())的Service对象。

o它包含着一个正在执行onReceive()方法的BroadcastReceiver对象。

任一时间下,仅有少数进程会处于前台,仅当内存实在无法供给它们维持同时运行时才会被杀死。一般来说,在这种情况下,设备已然处于使用虚拟内存的状态,必须要杀死一些前台进程以用户界面保持响应。

2.可视进程没有前台组件,但仍可被用户在屏幕上所见。当满足如下任一条件时,进程被认为是可视的:、

o它包含着一个不在前台,但仍然为用户可见的activity(它的onPause()方法被调用)。这种情况可能出现在以下情况:比如说,前台activity是一个对话框,而之前的activity位于其下并可以看到。

o它包含了一个绑定至一个可视的activity的服务。

可视进程依然被视为是很重要的,非到不杀死它们便无法维持前台进程运行时,才会被杀死。

3.服务进程是由startService()方法启动的服务,它不会变成上述两类。尽管服务进程不会直接为用户所见,但它们一般都在做着用户所关心的事情(比如在后台播放mp3或者从网上下载东西)。所以系统会尽量维持它们的运行,除非系统内存不足以维持前台进程和可视进程的运行需要。

4.背景进程包含目前不为用户所见的activityActivity对象的onStop()方法已被调用)。这些进程与用户体验没有直接的联系,可以在任意时间被杀死以回收内存供前台进程、可视进程以及服务进程使用。一般来说,会有很多背景进程运行,所以它们一般存放于一个LRU(最后使用)列表中以确保最后被用户使用的activity最后被杀死。如果一个activity正确的实现了生命周期方法,并捕获了正确的状态,则杀死它的进程对用户体验不会有任何不良影响。

5.空进程不包含任何活动应用程序组件。这种进程存在的唯一原因是做为缓存以改善组件再次于其中运行时的启动时间。系统经常会杀死这种进程以保持进程缓存和系统内核缓存之间的平衡。

Android会依据进程中当前活跃组件的重要程度来尽可能高的估量一个进程的级别。比如说,如果一个进程中同时有一个服务和一个可视的activity,则进程会被判定为可视进程,而不是服务进程。

此外,一个进程的级别可能会由于其它进程依赖于它而升高。一个为其它进程提供服务的进程级别永远高于使用它服务的进程。比如说,如果A进程中的内容提供者为进程B中的客户端提供服务,或进程A中的服务为进程B中的组件所绑定,则A进程最低也会被视为与进程B拥有同样的重要性。

因为运行着一个服务的进程重要级别总高于一个背景activity。所以一个activity以启动一个服务的方式启动一个长时间运行过程比简单的衍生一个线程来进行处理要好。尤其是当处理过程比activity本身存在时间要长的情况之下。我们以背景音乐播放和上传一个相机拍摄的图片至网站上为例。使用服务则不论activity发生何事,都至少可以保证操作拥有服务进程的权限。如上一节广播接收器生命周期所提到的,这也正是广播接收器使用服务,而不是使用线程来处理耗时任务的原因。



更多相关文章

  1. Android之Activities
  2. Android(安卓)Audio - 支持多个APK同时录音
  3. Android(安卓)从启动到程序运行发生的事情
  4. 开发Android第三步,签名证书,真机安装编译程序
  5. Android(安卓)WebView优化
  6. cocos2d-x 播放视频 on Android
  7. Android跨进程通信IPC之19——AIDL
  8. android 垂直 SeekBar 源代码(VerticalSeekBar)
  9. Android(安卓)不得不知Tag的妙用

随机推荐

  1. thinkphp3.2【空操作和空控制器使用】
  2. python django 基本测试 及调试 201812
  3. phpcms v9访问单网页一级栏目自动跳转到
  4. eclipse 编写php错误
  5. phpBB3导入帖子的Python脚本
  6. 如何将Composer中的CakePHP插件安装到app
  7. 如何使用background-image:用php
  8. 在Apache及IIS6.0中codeigniter去掉 URL
  9. php面向对象之抽象类和接口理解
  10. Thinkphp 使用原生类