基础篇-Service解析

来源:互联网 发布:正规淘宝客服兼职平台 编辑:程序博客网 时间:2024/06/16 03:34
一.service简介
Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。

使用关键:在于与Activity区别,是其在后台有独立运行的生命周期,执行后台任务。还有serviceactivity一样都存在与当前进程的主线程中,所以,一些阻塞UI的操作,比如耗时操作不能放在service里进行,比如另外开启一个线程来处理诸如网络请求的耗时操作。例如,电话盒子,局域网内UDP通信,后台线程端口监听,接收电话机发来信号,进行反馈,需要长时间启动。还有一些,比如后台菜单更新到本地数据库,多任务下载,临时后台服务,使用IntentService,后台任务执行结束后会自动停止,从而一定程度上避免了Service内存泄漏与后台服务驻留消耗内存,这些平时操作中关注程序性能优化

二.Service使用解析

1.通过startService来启动的Service
使用context.startService() 启动Service是会会经历:
service没有实例,启动时context.startService() ->onCreate()- >onStartCommand()—>onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop
service已经启动,调用startService后:onStartCommand()-->onStart() --> onDestroy

onStart已经不推荐用了,但是还是列一下吧,以及与onStartCommand()关系。Android2.0 API level之后,实现onStart等同于重写onStartCommand并返回START_STICKY 。
当我们通过调用了Context的startService方法后,我们便启动了Service,通过startService方法启动的Service会一直无限期地运行下去,只有在外部调用Context的stopService或Service内部调用Service的stopSelf方法时,该Service才会停止运行并销毁。

要想使用Service,首先我们要继承自Service,然后重写如下方法: 
onCreate, onStartCommand, onBind 和 onDestroy。 这几个方法都是回调方法,都是由Android操作系统在合适的时机调用的,并且需要注意的是这几个回调方法都是在主线程中被调用的。
onCreate: 执行startService方法时,如果Service没有运行的时候会创建该Service并执行Service的onCreate回调方法;如果Service已经处于运行中,那么执行startService方法不会执行Service的onCreate方法。也就是说如果多次执行了Context的startService方法启动Service,Service方法的onCreate方法只会在第一次创建Service的时候调用一次,以后均不会再次调用。我们可以在onCreate方法中完成一些Service初始化相关的操作。
onStartCommand: 在执行了startService方法之后,有可能会调用Service的onCreate方法,在这之后一定会执行Service的onStartCommand回调方法。也就是说,如果多次执行了Context的startService方法,那么Service的onStartCommand方法也会相应的多次调用。在onStartCommand中我们可以读取到通过startService方法传入的Intent对象,并且这三次的startId都不同,分别是1,2,3,每次调用startService都会自动分配一个startId,startId可以用来区分不同的startService的调用,一般情况下startId都是从1开始计数,以后每次调用startService之后startId自动加一递增,onStartCommand方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐,根据接收到的Intent数据,进行对于操作处理等。
onBind: Service中的onBind方法是抽象方法,所以Service类本身就是抽象类,也就是onBind方法是必须重写的,即使我们用不到。在通过startService使用Service时,我们在重写onBind方法时,只需要将其返回null即可。onBind方法主要是用于给bindService方法调用Service时才会使用到。
onDestroy: 通过startService方法启动的Service会无限期运行,只有当调用了Context的stopService或在Service内部调用stopSelf方法时,Service才会停止运行并销毁,在销毁的时候会执行Service回调函数。

需要注意:
(1)startService()方法和stopService()方法在执行完后立即返回结果,也就是这两个方法都不是阻塞式的,启动service和停止service都是异步操作,startService()、stopService()都是将intent对象发送给Android Framework层,然后Framework层异步地启动、停止Service。
(2)当Android面临内存匮乏的时候,可能会销毁掉你当前运行的Service,然后待内存充足的时候可以重新创建Service,Service被Android系统强制销毁并再次重建的行为依赖于Service中onStartCommand方法的返回值。
START_NOT_STICKY(不重建)、START_STICKY(重建不存intent)和START_REDELIVER_INTENT(重建存intent)、START_STICKY_COMPATIBILITY(不一定重启)

START_NOT_STICKY: 如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service,当然如果在其被杀掉之后一段时间又调用了startService,那么该Service又将被实例化。如果某个Service执行的工作被中断几次无关紧要或者对Android内存紧张的情况下需要被杀掉且不会立即重新创建这种行为也可接受,那么我们便可将 onStartCommand的返回值设置为START_NOT_STICKY。举个例子,某个Service需要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据。当执行到Service的onStartCommand时,在该方法内再规划一个N分钟后的定时器用于再次启动该Service并开辟一个新的线程去执行网络操作。假设Service在从服务器获取最新数据的过程中被Android系统强制杀掉,Service不会再重新创建,这也没关系,因为再过N分钟定时器就会再次启动该Service并重新获取数据。

START_STICKY: 如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY,比如一个用来播放背景音乐功能的Service就适合返回该值。

START_REDELIVER_INTENT: 如果返回START_REDELIVER_INTENT,表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。只要返回START_REDELIVER_INTENT,那么onStartCommand重的intent一定不是null。如果我们的Service需要依赖具体的Intent才能运行(需要从Intent中读取相关数据信息等),并且在强制销毁后有必要重新创建运行,那么这样的Service就适合返回START_REDELIVER_INTENT。

START_STICKY_COMPATIBILITYSTART_STICKY的兼容版本,但不保证服务被kill后一定能重启


2.通过bindService来启动的Service
 (1)只有activities,services,contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service
(2)bindService启动的服务在调用者和服务之间是典型的client-server的接口,即调用者是客户端,service是服务端,service就一个,但是连接绑定到service上面的客户端client可以是一个或多个,客户端client(即调用bindService的一方,比如某个Activity)可以通过IBinder接口获取Service的实例,从而可以实现在client端直接调用Service中的方法以实现灵活的交互,并且可借助IBinder实现跨进程的client-server的交互,这在纯startService启动的Service中是无法实现的
(3)bindService启动的服务的生命周期与其绑定的client息息相关。当client销毁的时候,client会自动与Service解除绑定,当然client也可以通过明确调用Context的unbindService方法与Service解除绑定。当没有任何client与Service绑定的时候,Service会自行销毁。
(4)startService和bindService二者执行的回调方法不同:startService启动的服务会涉及Service的的onStartCommand回调方法,而通过bindService启动的服务会涉及Service的onBind、onUnbind等回调方法。
使用context.bindService()启动Service会经历:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop

(5)使用bindService主要分两种情形: 
即Service的调用者client与Service在同一个App中,该情形也是我们在实际开发中用到最多的情形,
从你的客户端绑定到一个service,你必须:
· 1实现ServiceConnection.你的实现必须重写两个回调方法:onServiceConnected()系统调用这个来传送在serviceonBind()中返回的IBinder 另一个OnServiceDisconnected():Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.

· 2调用bindService(),传给它ServiceConnection的实现.

· 3当系统调用你的onServiceConnected()方法时,你就可以使用接口定义的方法们开始调用service了.

· 4要与service断开连接,调用unbindService()
PS:1onStart可以多次调用,onBind只调用一次。
   2service混合调用时要stopunbind两者都执行后之后才会销毁

最后我们将bindService启动的Service的生命周期总结为如下的流程图:



另一种是远程服务:Service的调用者client是App1中的一个Activity,而Service是App2中的Service,client与service分属两个App,这种情形下就要涉及Android跨进程通信机制了,下篇在来整理.


三.IntentService

总结IntentService的特点如下:
1、IntentService是Service类的子类,用来处理异步请求。
2、IntentService是不适合用于bindService()这样的启动方式的。其次我们通过startService多次启动Service时,相当于在MessageQueue中添加了多个任务,就可以实现多任务按照顺序执行。
3、IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。
4、执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务,Intent的生命周期跟你的 处理的任务是一致的. 所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出
5、IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread所对应的子线程。 ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。
只有在onHandleIntent()方法中执行的代码才是在工作线程中运行的。 
2 0
原创粉丝点击