Service
MoMo Lv5
  • Service的启动方式,启动方式的区别?
  • Service的生命周期
  • Activity、Service、intent之间的联系
  • 在Activity和Service中创建Thread的区别
  • android进程的优先级?以及如何保证Service不被杀死
  • 直接在Activity中创建一个thread跟在service中创建一个thread之间的区别

什么是Service

Service意为“服务”,相对于Activity是一个有可见界面的、为实现交互而提供的Android应用组件,Service则是一个可以在后台长期运行但又不使用用户界面的Android应用组件。它可以和其他的组件形成一定联系,通过传达信息来联系多个组件共同执行某个操作。举个最简单的例子,你此时正在用手机听歌曲,播放歌曲的进程就是一个后台服务。

Service的启动方式

对于Service的生命周期,不同的启动方式会有不同的生命周期,所以了解不同的启动方式的同时,也要掌握Service的生命周期。 图片说明

startService()

image
生命周期见上图左时序图。当另一个组件可以通过调用 startService()方法来启动特定的服务,此时Service生命周期中的onStartCommand()方法被调用。当调用startService()方法时,其他组件需要在方法中传递一个intent参数,服务会在onStartCommand()中接收到intent并获取一些数据。比如ActivityA需要上报一些用户数据到服务器上面,就可以通过startService()来启动ServiceA,并将需要上报的数据传递给ServiceA,在ServiceA里面调用一些网络接口,把数据直接上报到服务器上面。

当一个服务以这种方式启动时,它的生命周期不再受启动它的组件的影响,它可以在后台无限期地运行,如上一段的例子里,就算ActvityA挂了,ServiceA仍在后台运行,直到ServiceA自己调用stopSelf()或者其他的组件手动调用stopService(ServiceA)时ServiceA才会停止。

bindService()

生命周期见上图右侧时序图。从名字上可以看出这个“绑定”一个服务,要创建一个支持绑定的Service,我们必须要重写它的onBind()方法,这个方法返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。如ActivityA绑定ServiceA,此时ActivityA称为客户端,ServiceA称为服务端,ActivityA有从ServiceA返回的一个IBinder对象,通过该对象,ActivityA就可以调用ServiceA里面的方法。

这是一种比startService更复杂的启动方式,同时使用这种方式启动的service也能完成更多的事情,比如其他组件可向其发送请求,接受来自它的响应,甚至通过它来进行IPC等等。

两种启动方式的区别

通过startService启动

生命周期顺序:onCreate->onStartCommand->onDestroy

如上述说的,只要通过startService()启动的服务,就会一直在后台运行,直到有其他组件调用stopService()或者自己调用stopSelf()才会结束

注意点:

startService时,如果该服务未创建,则会触发 onCreate 和 onStartCommand,以后在服务运行过程中,每次startService都只会触发onStartCommand;

不论startService多少次,只要调用一次stopService,该服务就会停止;

通过bindService绑定

生命周期顺序:onCreate->onBind->onUnBind->onDestroy

如果一个Service在某个Activity中通过调用bindService方法来绑定,不论bindService被调用几次,Service的onCreate和onBind方法只会执行一次,此时注意,这种方式绑定的服务不会调用onStartCommand方法。当Activity调用unBindService或者Activity挂掉,则服务会停止;

startService/bindService同时使用

这种情况很好理解,符合“加减法定律”。我们完成可能startService启动一个服务的的同时又bindService绑定一个服务:

因为通过startService启动,所以该Service将会一直在后台运行,onCreate方法只有在第一次startService时调用,onStartCommand的调用次数与startService调用的次数一致
这种情况需要同时stopService和unbindService方法, onDestroy方法才会被执行,缺一不可。

附:为什么bindService可以跟Activity生命周期联动?

1、bindService方法执行时,LoadedApk会记录ServiceConnection信息;

2、Activity执行finish方法时,会通过LoadedApk检查Activity是否存在未注销/解绑的 ServiceConnection,如果有,那么会通知AMS注销/解绑对应的Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操作。

在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?

如果你要启动的服务是需要后台长期运行,并且你经常需要使用到这个服务的,那么使用 startService 便可以了,比如我要经常上报数据到远程服务器,那么就用startService来启动负责数据上报的服务;

如果你只是要用到服务里的某个接口,使用频率也不高,因此不需要服务一直运行,而是等到需要使用接口的时候,通过bindService去绑定服务,创建该服务实例,调用完就解绑服务。这种方式可以节省很多系统资源,当然也要注意每次都要创建服务是需要花费一定时间的,只是相对于让服务一直运行后台,我们更愿意每次重新创建;

如果你想要与正在运行的 Service 取得联系,那么就可以通过 bindService来绑定服务,获取服务在本地的代理,也就是上面说的IBinder,通过IBinder来和Service取得联系。此时就同时使用 startService 和 bindService 了。

Service种类和优先级

Service的种类

按运行地点划分

  • 本地服务: 该服务依赖于主进程,而非独立的进程,因此在一定程度节约了资源,且和主进程的通讯更简单,不过如果主进程挂了,该服务就终止。如一个主进程启动一个本地网络服务,将一些数据上报到远程服务器后,就可以停止该本地网络服务。
  • 远程服务: 该服务独立于主进程,是一个独立的进程。不受其他进程的影响,多个进程都可以通过AIDL(这个后续会讲到,TODO)单独与该服务进行IPC通讯,因此较为复杂,且这种服务一般长期运行在后台。典型的例子就是系统服务。

按运行类型划分

  • 后台服务: 默认的服务都是后台服务,也就是startService()启动的服务,服务终止时用户是无法感知的,如天气更新等服务;
  • 前台服务: 后台服务优先级较低,可能会被系统杀死,可以将后台服务提高为前台服务,是会在状态栏显示图标的服务,如常见的音乐播放服务,服务终止,状态栏的图标也消失;
  • 可交互的后台服务: 服务本来是无法和用户交互的,但可以先用Activity和用户交互,同时Activity通过bindSerive()绑定服务,进而实现“可交互的后台服务”。

android中进程的优先级

Service和Activity,一起看下Android中进程的优先级。以下优先级由高到低。

  • 前台进程:即与用户交互的Activity,以及Activity所使用的Service等,如果系统不足,最晚会杀死前台进程;
  • 可见进程:对用户可见,但不能与用户交互的Activity或者绑定在其上面的Service。
  • 服务进程:正使用StartService方法运行的服务,对用户是不可见的,但却是用户关心。例如正在看小说时,后台播放音乐的服务进程,如果此时系统需要空间运行,会先停止音乐服务,再停止看小说的进程。
  • 后台进程:运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这时的进程系统一旦没了有内存就首先被杀死
  • 空进程:不包含任何应用程序的进程,这样的进程系统是一般不会让他存在的。

如何保证Service不被杀死?

总有时候希望自己增加的Service不被系统杀死。增加Service可以使用自定义系统服务来添加到系统里,不过涉及自定义系统服务的,是Android系统开发工程师才能做到的,更常见的是使用apk应用程序的形式添加到系统里面。

  • 使用自定义系统服务:自定义系统服务原则上是不会被系统杀死的,因此,一些重要的服务可以考虑用自定义系统服务来实现;
  • 使用系统服务来监控:先弄一个白名单,记录需要监控的应用的包名,再自定义一个系统服务,监控系统里某个应用被杀死,如果该应用在白名单上,则重新拉起应用;
  • 设置为前台服务,前台服务的优先级更高,不会轻易被杀死;
  • 使用第三方库来保活,如HelloDaemon;
  • 使用双进程Service,在ServiceA和ServiceB相互保护,检测到有一个Service被杀死则重新拉起;
  • 特殊操作拉起服务:在亮屏、开机等特殊操作手动的拉起服务;
  • 使用闹钟循环拉起服务;
  • 应用程序添加SystemUID,使应用程序成为系统应用,比如手机桌面的下拉框就是一个系统应用,叫做SystemUI;
  • Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样;

Activity、Intent、Service 是什么关系

这三者是Android开发中使用最频繁的类啦。其中Activity和Service是大名鼎鼎Android的四大组件之二。其父类都是Context,因此两者是兄弟关系。其中Activity负责用户交互界面的显示和交互逻辑的实现,Service则负责后台任务的处理。而Intent意为“意图”,像一座桥梁一样,负责Activity和Service之间的数据传递。

直接在Activity中创建一个thread跟在service中创建一个thread之间的区别

  • 在Activity中创建:该线程负责完成该Activity的某个特殊任务,特别是耗时的任务,等Activity被销毁后,线程就没有生存的意义了,也应该销毁。
  • 在Service中创建:一般在Service的线程是为了长期存在于后台,完成某种特殊任务。只要服务没有挂掉,该线程就一直在后台跑。比如在Service中保持与服务器的长连接。
Powered by Hexo & Theme Keep
Unique Visitor Page View