Service

概述

Service是一个可以在后台长时间运行且不需要和用户进行交互的应用组件;
它的运行不依赖任何的用户界面,不是运行在一个独立的进程里面,而是依赖于创建Service时所在的应用程序进程,当进程被杀掉,Service也会被杀掉。并且Service的代码默认运行在主线程中,除非在Service中手动开启一个子线程。

生命周期

在这里插入图片描述
用法:首先定义一个Service类继承自Service(此时必须重写onBind()方法,因为这个方法是一个抽象方法,并且是唯一一个)
oonCreate()
创建服务的时候调用,该方法只会被调用一次。
oonStartCommand()
每次调用startService时调用。一旦执行此方法,Serviceiu会永久的在后台执行下去,直到我们执行stopSelf或者stopService来停止服务。
oonBind
每次调用bindService时调用,系统就可以通过Binder来实现Activity和Service之间的相互通信;

oonUnbind()
调用过bindService的服务在销毁前会调用这个方法,表示即刻解绑
oonDestory()
服务销毁的时候调用。可以在此清理所有的资源,如线程,注册的侦听器,接收器等
一般情况下,如果我我们希望服务一启动的时候就去执行某个动作,就可以将其写在onStartCommand()里面。

执行startService时,Service会经历onCreate->onStartCommand。

当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。

执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。

调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。

多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。

第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务。

onStartCommand(Intent intent,int flags,int startId)的参数

oIntent
启动时,启动组件传递过来的intent,如Activity可以利用Intent封装所需要的参数并传递给Service;
oFlags
表示启动请求时是否有额外数据,可选值有0,START_FLAG_REDELIVERY,START_FLAG_RETRY;0代表没有
START_FLAG_REDELIVERY
代表了onStartCommand方法的返回值为START_REDELIVER_INTENT,而且在上一次服务被杀死前会去调用stopself方法停止服务,其中START_REDELIVER_INTENT意味着当Service因内存不足而被系统kill之后,则会重建服务,并且通过传递给服务的最后一个Intent调用onStartCommand(),此时的intent是有值的。
START_FLAG_RETRY
代表当onStartCommand调用后一直没有返回值时,会尝试重新去调用onStartCommand()。
ostatrId
指明当前服务的唯一ID,与stopSelfResult(int startId)配合使用,stopSelfResult可以更安全地根据ID停止服务。

onStartCommand的返回值int类型

START_STICKY,START_NOT_STICKY,START_REDELIVER_INTENT
oSTART_STICKY
当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。
oSTART_NOT_STICKY
当Service因内存不足而被系统kill后,即使系统内存再次空闲时,系统也不会尝试重新创建此Service。除非程序中再次调用startService启动此Service,这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。

oSTRAT_REDELIVER_INTENT

当Service因内存不足而被系统kill后,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand(),任何挂起 Intent均依次传递。与START_STICKY不同的是,其中的传递的Intent将是非空,是最后一次调用startService中的intent。这个值适用于主动执行应该立即恢复的作业(例如下载文件)的服务。

启动方法

单独调用startService()或者bindService()都可以启动服务

单独调用startService()

onCreate()→onStartCommand()
调用stopSelf()或者stopService()以后:onDestroy()
startService只需要一个参数,就是指定要开启的Service。就是正常Activity跳转的写法。
当调用startService后,如果Service是首次启动就会调用onCreate然后再调用onStartCommand。
如果是启动之后再次调用,就只会调用onStartCommand。
启动之后我们需要手动再调用stopSelf或者stopService来停止服务
当调用stopSelf或者stopService,就会调用onDestroy,将Service摧毁掉。

单独调用bindService()

onCreate()→onBind()(注意这里不会回调onStartCommand方法),调用unbindService()后:onUnbind()→onDestroy()。
bindService就是绑定服务。需要额外定义一个ServiceConnection来接收bindService的状态。
ServiceConnection需要重写三个方法,分别是:
onServiceConnected:和服务绑定成功后会调用
onNullBinding:onBind返回null时会调用此方法
onServiceDisconnected:当服务终止时会调用此方法
当通过bindService绑定时不会调用onStartCommand,而是去调用onBind方法。而在onBind方法中,必须返回一个IBinder对象,供他和Activity之间进行通信。
但是当不需要再用service之后,需要调用unbindService进行解绑。当启动方摧毁时,service也会自动unBind

二者都用

如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStart方法便会调用多少次。Service的终止,需要unbindService和stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不
存在了(如Activity被finish的时候)之后,服务才会自动停止。

那么,什么情况下既使用startService,又使用bindService呢?
如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。
另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)。

IntentService

IntentService是一个异步的,会被自动停止的服务

因为Service默认运行在主线程中,所以当我们想要在服务中做一些耗时操作时,我们就需要在onStartCommand方法中开启一个线程,否则可能会发生ANR。如果想要在服务执行完后自动停止,就需要在run方法中手动调用stopSelf方法。但这样实现比较麻烦,并且容易忘记开启线程或忘记调用stopSelf方法,因此就有了这个IntentService类。

简单使用

和自定义Service类似,只需要继承IntentService重写onHandleIntent方法即可。

原理

在第一次调用startService时会调用onCreate方法,其中会创建一个HandlerThread来启动一个子线程并创建子线程的Handler。多次调用startService时,只有第一次会创建实例,而每次会通过onStartCommand方法向子线程发送一个消息。子线程的Handler在取出消息后,它的handleMessage方法会调用onHandleIntent来在子线程执行耗时任务,执行完任务后会调用stopSelf()停止子线程。

为什么不调用bindService实现ServiceIntent?

IntentService的工作原理是,在IntentService的onCreate()里会创建一个HandlerThread,并利用其内部的Looper实例化一个ServiceHandler对象;而这个ServiceHandler用于处理消息的handleMessage()方法会去调用IntentService的onHandleIntent(),这也是为什么可在该方法中处理后台任务的逻辑;当有Intent任务请求时会把Intent封装到Message,然后ServiceHandler会把消息发送出,而发送消息是在onStartCommand()完成的,只能通过startService()才可走该生命周期方法,因此不能通过bindService创建IntentService。

更新UI

虽然Service运行在主线程,但是他是无法直接更新UI的。(因为service里并没有Activity或者view的实例)
我们可以通过
1.binder
2.handler
3.AIDL
4.Broadcast

Service和Activity通信

Binder

如果直接使用Binder,我们首先需要通过在Service中自定义一个Binder类,在类里面可以写一些方法,然后我们创建这个Binder的对象,通过Service的onBind方法将这个对象返回出去。
然后再Activity中首先我们需要创建这个Service的Binder类的对象,然后在ServiceConnection的onServiceConnected方法中设置让binder对象等于传过来的Binder对象,这样我们就可以通过这个Binder对象去调用我们定义的方法去进行控制Service了。

Messenger

首先我们需要在Service中创建一个Messenger对象并绑定Handler,重写handler 的handleMessage方法,然后在方法中我们我们就可以拿到消息msg,并可以调动msg的replyTo.send方法重新给消息发送者返回消息。然后再onbind方法中return Messenger.getBinder。这样我们在Activity的ServiceConnection的onServiceConnected方法中拿到这个Messenger的Binder对象,然后我们在Activity中new一个Service中的Messenger对象,这样我们就可以调用messenger的构造方法传入这个Binder拿到Service的Messenger对象了。
然后同样的,我们也需要Activity中创建一个Messenger对象并绑定Handler,然后重写Handler的handleMessage方法,在这我们可以对Service发送过来的消息进行处理。然后我们可以在我们需要的地方构建Message,输入我们想要传递的信息,然后让他的replyTo参数等于我们Activity中的Messenger对象,然后用Service的Messenger对象去发送这个消息。
这样,我们从Activity中发送的消息会被Service的handlerMessage接收到,然后他又会通过message.reply.send方法重新给我们的Activity返回一个消息。

如何保证Service不被杀死?

1.在Service的onStartCommand()返回START_STICKY,这样就能在Service被杀死后再次启动。但是不能保证任何情况下都被重建,比如进程被干掉了。
2.使用前台Service
3.提升service优先级:在AndroidManifest.xml文件中对于intent-filter可以通过**android:priority = “1000”**这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
1.在Activity的onDestroy中发送一个广播,然后在广播接收者的onReceive()里面启动Service

前台服务

为什么要使用前台服务?

在一般情况下,Service几乎都是在后台运行,一直默默地做着辛苦的工作。但这种情况下,后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收。
那么,如果我们希望Service可以一直保持运行状态且不会在内存不足的情况下被回收时,可以选择将需要保持运行的Service设置为前台服务。
例:App中的音乐播放服务

如何创建一个前台服务?

新建一个服务
重写onStartCommand方法,在StartCommand方法中去构建一个Notification
启动服务
在onStartCommand中调用startForeground将这个notification传进去去启动这个前台服务
停止服务
在onDestroy中调用sopForeground去关闭

Service和Thread的区别,为什么有Thread还有Service?

其实Service更重要的作用就是能让他独立于Activity去进行操作。虽然后台任务可以在Activity中通过Thread去执行,但是一方面Activity管理的东西已经够多了,还让他去管理Thraed就显得更复杂了,其次,后台任务并不是指子线程,而是真正的后台,如果只是在Activity中使用Thread的话,当这个Activity退出前台后这个Thread就没有意义了,而Service却能独立于Activity去执行任务,实现了真正意义上的后台。
其次,Service的后台优先级是高于挂起的Activity,所以可以更好的去执行后台任务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值