Service
Service
1、启动模式
1.1 StartService() 模式
生命周期:onCreate()->onStartComment()->onDestroy()
生命周期见上图左时序图。当另一个组件可以通过调用 startService()方法来启动特定的服务,此时Service生命周期中的onStartCommand()方法被调用。当调用startService()方法时,其他组件需要在方法中传递一个intent参数,服务会在onStartCommand()中接收到intent并获取一些数据。比如ActivityA需要上报一些用户数据到服务器上面,就可以通过startService()来启动ServiceA,并将需要上报的数据传递给ServiceA,在ServiceA里面调用一些网络接口,把数据直接上报到服务器上面。
当一个服务以这种方式启动时,它的生命周期不再受启动它的组件的影响,它可以在后台无限期地运行,如上一段的例子里,就算ActvityA挂了,ServiceA仍在后台运行,直到ServiceA自己调用stopSelf()或者其他的组件手动调用stopService(ServiceA)时ServiceA才会停止。
1.2 BindService()模式
生命周期:onCreate()->onBind()->onUnBind()->onDestroy()
生命周期见上图右侧时序图。从名字上可以看出这个“绑定”一个服务,要创建一个支持绑定的Service,我们必须要重写它的onBind()方法,这个方***返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。如ActivityA绑定ServiceA,此时ActivityA称为客户端,ServiceA称为服务端,ActivityA有从ServiceA返回的一个IBinder对象,通过该对象,ActivityA就可以调用ServiceA里面的方法。
生命周期受Activity影响,Activity结束,Service也就结束了
1.3 startService/bindService同时使用
我们完成可能startService启动一个服务的的同时又bindService绑定一个服务:
- 因为通过startService启动,所以该Service将会一直再后台运行,onCreate方法只有在第一次startService时调用,onStartCommond的调用次数和startService调用次数一致
- 这种情况需要同时stopService和unbindService方法, onDestroy方法才会被执行,缺一不可。
1.4 为什么bindService可以跟Activity生命周期联动?(附加题)
- bindService方法执行时,LoadedApk会记录ServiceConnection信息;
- Activity执行finish方法时,会通过LoadedApk检查Activity是否存在未注销/解绑的 ServiceConnection,如果有,那么会通知AMS注销/解绑对应的Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操作。
1.5 在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?
- 如果你要启动的服务是需要后台长期运行,并且你经常需要使用到这个服务的,那么使用 startService 便可以了,比如我要经常上报数据到远程服务器,那么就用startService来启动负责数据上报的服务;
- 如果你只是要用到服务里的某个接口,使用频率也不高,因此不需要服务一直运行,而是等到需要使用接口的时候,通过bindService去绑定服务,创建该服务实例,调用完就解绑服务。这种方式可以节省很多系统资源,当然也要注意每次都要创建服务是需要花费一定时间的,只是相对于让服务一直运行后台,我们更愿意每次重新创建;
- 如果你想要与正在运行的 Service 取得联系,那么就可以通过 bindService来绑定服务,获取服务在本地的代理,也就是上面说的IBinder,通过IBinder来和Service取得联系。此时就同时使用 startService 和 bindService 了。
2 Service的种类和优先级
2.1 Service的种类
- 后台service
- 前台service
- 本地service
- 远程service
按地点分:
- 本地服务:该服务依赖于主进程,而非独立的进程,因此在一定程度节约了资源,且和主进程的通讯更简单,不过如果主进程挂了,该服务就终止。如一个主进程启动一个本地网络服务,将一些数据上报到远程服务器后,就可以停止该本地网络服务。
- 远程服务:该服务独立于主进程,是一个独立的进程。不受其他进程的影响,多个进程都可以通过AIDL(这个后续会讲到,TODO)单独与该服务进行IPC通讯,因此较为复杂,且这种服务一般长期运行在后台。典型的例子就是系统服务。
按运行类型分:
- 后台服务:默认的服务都是后台服务,也就是startService()启动的服务,服务终止时用户是无法感知的,如天气更新等服务;
- 前台服务:后台服务优先级较低,可能会被系统杀死,可以将后台服务提高为前台服务,是会在状态栏显示图标的服务,如常见的音乐播放服务,服务终止,状态栏的图标也消失;
- 可交互的后台服务:服务本来是无法和用户交互的,但可以先用Activity和用户交互,同时Activity通过bindSerive()绑定服务,进而实现“可交互的后台服务”。
2.2 service的优先级
前台进程
可见进程
服务进程
后台进程
空进程
Service和Activity,一起看下Android中进程的优先级。以下优先级由高到低。
- 前台进程:
即与用户交互的Activity,以及Activity所使用的Service等,如果系统不足,最晚会杀死前台进程;
- 可见进程:
对用户可见,但不能与用户交互的Activity或者绑定在其上面的Service。
- 服务进程:
正使用StartService方法运行的服务,对用户是不可见的,但却是用户关心。例如正在看小说时,后台播放音乐的服务进程,如果此时系统需要空间运行,会先停止音乐服务,再停止看小说的进程。
- 后台进程:
运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这时的进程系统一旦没了有内存就首先被杀死
- 空进程:
不包含任何应用程序的进程,这样的进程系统是一般不会让他存在的。
3.3 如何保证service不被杀死
1、使用自定义的服务
2、使用两个service,当其中的一个service挂了,用另一个service启动
答案:
- 使用自定义系统服务:自定义系统服务原则上是不会被系统杀死的,因此,一些重要的服务可以考虑用自定义系统服务来实现;
- 使用系统服务来监控:先弄一个白名单,记录需要监控的应用的包名,再自定义一个系统服务,监控系统里某个应用被杀死,如果该应用在白名单上,则重新拉起应用;
- 设置为前台服务,前台服务的优先级更高,不会轻易被杀死;
- 使用第三方库来保活,如HelloDaemon;
- 使用双进程Service,在ServiceA和ServiceB相互保护,检测到有一个Service被杀死则重新拉起;
- 特殊操作拉起服务:在亮屏、开机等特殊操作手动的拉起服务;
- 使用闹钟循环拉起服务;
- 应用程序添加SystemUID,使应用程序成为系统应用,比如手机桌面的下拉框就是一个系统应用,叫做SystemUI;
- Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样;
3、说说Activity、Intent、Service 是什么关系?
Activity是属于页面的交互和展示,Intent可以在Activity中进行数据的传输,Service属于一种后台进程
4、直接在Activity中创建一个thread跟在service中创建一个thread之间的区别?
- Activity中创建:该线程负责完成该Activity的某个特殊的任务,特别是耗时的任务,等Activity销毁后,线程就没有意义了,也就销毁了
- Service中创建:因为Service是后台线程,只要服务没有挂掉,线程就可以一直运行
5 Service和Activity如何进行通信
- 在service中添加一个继承Binder的内部类,并添加相应的方法
- service中重写service的onbind方法,返回我们刚刚定义的那个内部类的实例
- Activity中绑定服务,重写serviceConnection,onserviceConnection时返回的IBinder调用逻辑方法
6 .IntentService是什么,IntentService原理,应用场景及其与Service的区 别
IntentService 是 Service 的子类,默认开启了一个工作线程HandlerThread,使用这个工作线程逐一处理所有启动 请求,在任务执行完毕后会自动停止服务。只要实现一个方法 onHandleIntent,该方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。
可以启动 IntentService 多次,而每一个耗时操作会以队列的方式在 IntentService 的 onHandlerIntent 回调方法中 执行,并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服 务。
如何使用:
- 创建一个名叫 ServiceHandler 的内部 Handler
- 把内部Handler与HandlerThread所对应的子线程进行绑定
- HandlerThread开启线程 创建自己的looper
- 通过 onStartCommand() intent,依次插入到工作队列中,并发送给 onHandleIntent()逐个处理
应用场景:
后台下载任务,静默上传
7 bindService和startService混合使用的生命周期以及怎么关闭
如果先启动Bind service 后启动start Service
生命周期:onCreate()->onStartCommand()->onBind()
如果先启动start Service后启动BindService
生命周期:onCreate()->onBind()->onStartCommand()
如果只是stop Service
service的onDestroy方法不会立即执行,在Activity退出的时候才会执行onDestroy()
如果只是unbindService
只有onUnbind()方法会执行,ondestroy()不会执行
如果要完全退出Service,那么就得执行unbindService()以及stopService。