1. Service 是什么(What)?
Service是一种在Android应用后台的一种组件,没有自己的界面,不需要与用户交互。
1)Android 中的一个应用组件?(生命周期方法)
2)Android 中的一个后台服务?(可以长时间运行于后台)
最基本的两种用途:执行长时间时间运行的耗时操作,如网络下载,音乐播放,文件系统检测。
一种是组件间的交互(通过将某些功能以Service组件的形式进行封装,然后提供给其他应用组件调用,而不管这些组件是否与Service组件在同一进程中)。
FAQ?
1)对于长时间的耗时操作是直接起工作线程,还是启service?
建议:在Service中启工作线程。
2)为什么不在activity启工作线程执行耗时操作呢?
因为当activity工作于后台处于停止状态时,它所
在进程的生命力就会比较薄弱,在内存不足时可
能会被杀死。
2、Service 与 Thread 的区别
很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。
1).Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2).Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。
在Android 中的进程可以分为如下几种类型
1)前台进程(可见,可以与用户交互)
2)可见进程(可见,但不能与用户交互)
3)服务进程(后台有service在运行)
4)后台进程(没有service组件,所有的activity都处于停止状态)
5)空进程(没有任何组件在运行的进程)
以上进程的生命力,从高到低。
按运行地点分类:
类别 | 区别 | 优点 | 缺点 | 应用 |
本地服务(Local) | 该服务依附在主进程上, | 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。 | 主进程被Kill后,服务便会终止。 | 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。 |
远程服务(Remote) | 该服务是独立的进程, | 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 | 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 | 一些提供系统服务的Service,这种Service是常驻的。 |
其实remote服务还是很少见的,并且一般都是系统服务。
按运行类型分类:
类别 | 区别 | 应用 |
前台服务 | 会在通知一栏显示 ONGOING 的 Notification, | 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification。 | 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。 |
有同学可能会问,后台服务我们可以自己创建 ONGOING 的 Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成为 前台服务。这样做的好处在于,当服务被外部强制终止掉的时候,ONGOING 的 Notification 任然会移除掉。
按使用方式分类:
类别 | 区别 |
startService 启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService |
bindService 启动的服务 | 该方法启动的服务要进行通信。停止服务使用unbindService |
startService 同时也 bindService 启动的服务 | 停止服务应同时使用stepService与unbindService |
以上面三种方式启动的服务其生命周期也有区别,将在随后给出。
2.Android 中的Service 的应用场合?(when,why)
执行长时间耗时操作时时,可以考虑在service
组件中执行,例如音乐的播放,股票信息的时
时加载等。
记住:并不是耗时都要写到service,短时间的
耗时完全可以在activity中启工作线程执行。
Android中Service 的类型?
1) 启动模式的Service
如果Service组件是长时间运行的操作,则一般采用启动模式,采用启动模式的Service一般持续执行一个单一的操作,而且并不会向调用者返回任何信息。Service被启动后,将一直处于运行状态,即使调用startService的进程结束了,Service仍然还存在,直到有进程调用stopService,或者Service调用stopSelf自杀。
2) 绑定模式的Service
如果Service组件提供一种封装的功能供其他组件使用,则一般采用绑定模式。步骤:通过调用组件对象的bindService方法启动Service对象实例,如果没有指定的Service实例被创建,则该方法调用Service的onCreate()方法来创建一个实例,实例启动后,将调用onBind()方法,onBind方法返回给客户端一个IBinder接口实例,IBinder允许客户端回调Service方法,不如得到Service运行的状态或其他操作。只要连接建立,Service就会一直运行,(不管客户是否保留Service的IBinder的引用)。通常IBinder是一个使用AIDL写成的复杂接口。
3)混合模式的Service
我们在理解这些模式的service时,需要重点掌握
这些模式service对象的生命期,以及其生命周期
方法,我们可以在对应的生命周期方法中执行业
务。
***启动模式的Service
1、启动模式下的Service
实现步骤:1、创建Service类,继承android.app.Service类
2、实现onStartCommand等生命周期方法。
3.在Andridmanifest.xml文件中配置Service组件。
由于Service是在主线程运行的,为避免产生应用无响应异常,必须在Service类的内部创建一个单独的线程,用于耗时的业务逻辑。
Android SDK提供了更好的方法,既IntentService(同时解决了多请求下线程同步的问题)。
IntentService:
1、在应用的主线程外创建一个单独的工作线程来执行传递到onStartCommand方法的Intent组件。
2、创建一个工作队列,它每次将一个Intent传递到onHandleIntent(),不需要考虑多线程的同步问题。
3、当所有请求被处理完成后,将自动停止服务而不需要显示调用stopSelf方法。
4、提供一个返回null值的onBind方法的默认实现。
5、提供了onStartCommand方法的默认时间,它将所有的Intent发送到一个工作队列,并进一步发送到onHandleInteng方法。
运行模式:
在启动模式下,Service中的业务逻辑主要在onStartCommand方法中实现,每次通过调用方法startService来启动Service,都会调用onStartCommand方法,其中方法的返回值决定了Service的运行模式。
1、START_NOT_STICKY:如果Sevice在启动后,被kill掉,并且没有新启动的Intent传给它,那么将Service移出启动状态并且不重新生成,知道再次显示调用Context.startService。适用场景:网上下载数据。
2、START_REDELIVER_INTENT:如果Service进程在启动后kill掉,那么它将会被重启,并且最后传给他的Intent通过onStartCommand(Intent ,int,int)会被重新传给他,这种模式保证了传给它Intent一定会被处理完毕,适用场景:关键业务处理。
3、START_STICKY:如果Service在它启动后被kill掉,那么Android将让Service继续保持started状态,但是不保留启动它的Intent,Android将重新创建Service实例,并执行onStartCommand方法,如果此时没有新的Intent请求,此时Intent的参数是null,这一点要特别注意。适用场景:后台播放音乐。这种运行模式的特点是需要显示启动并停止Service。
启动模式service的启动和关闭
1)通过startService方法启动
2)通过stopService停止,在内部可以通过stopSelf(startId)去停止
**启动模式Service对象的生命周期方法:
1)onCreate(service创建时执行)
2)onStartCommand(每次启动都会执行)
3)onDestory(service销毁时会执行)
生命周期
使用context.startService()启动Service是会会经历:
context.startService()->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy()->Service stop
context.startService()->onCreate()->onStart()->Servicerunning->context.stopService()-> onDestroy()-> Servicestop
如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
所以调用startService的生命周期为:onCreate --> onStart(可多次调用) -->onDestroy
Serivce 的子类IntentService的应用?
IntentService会默认启动一个工作线程,我们
可以将耗时操作放在onHandleIntent中,此方
法执行结束,service会自动关闭。
FAQ?
1)启动模式Service 的粘性?(参考onStartCommand方法的返回值)
2)启动模式Service 如何通过隐式Intent启动
a)隐式意图需要在清单配置文件配置intent-filter
切记:service不用了,要记得停止。