服务组件
服务
1.定义
Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。
2.何时释放?
仅当内存过低且必须回收系统资源以供具有用户焦点的 Activity 使用时,Android 系统才会强制停止服务。如果将服务绑定到具有用户焦点的 Activity,则它不太可能会终止;如果将服务声明为在前台运行(稍后讨论),则它几乎永远不会终止。或者,如果服务已启动并要长时间运行,则系统会随着时间的推移降低服务在后台任务列表中的位置,而服务也将随之变得非常容易被终止;如果服务是启动服务,则您必须将其设计为能够妥善处理系统对它的重启。 如果系统终止服务,那么一旦资源变得再次可用,系统便会重启服务(不过这还取决于从 onStartCommand() 返回的值,本文稍后会对此加以讨论)。如需了解有关系统会在何时销毁服务的详细信息,请参阅进程和线程文档。
===内存不足时,普通服务会被强行终止,前台服务则不会,与有焦点的activity绑定的服务也不会。
3.清单文件服务元素
在清单文件服务元素时添加 android:exported 属性并将其设置为 "false",服务仅适用于您的应用。
还可将其他属性包括在 <service> 元素中,以定义一些特性,如启动服务及其运行所在进程所需的权限,android:name 属性是唯一必需的属性,用于指定服务的类名。
请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。 启动哪个服务存在一定的不确定性,而如果对这种不确定性的考量非常有必要,则可为服务提供 Intent 过滤器并从 Intent 中排除相应的组件名称,但随后必须使用 setPackage() 方法设置 Intent 的软件包,这样可以充分消除目标服务的不确定性。
4.服务内启动新线程
默认情况下,服务与服务声明所在的应用运行于同一进程,而且运行于该应用的主线程中,为了避免影响应用性能,您应在服务内启动新线程。
5.创建启动式服务
从传统上讲,您可以扩展两个类来创建启动式服务:Service、IntentService
6.IntentService ,注意它是创建启动式服务的。
这是 Service 的子类,它使用工作线程逐一处理所有启动请求。如果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现 onHandleIntent() 方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。
- 它创建了一个工作线程,线程里有个工作队列,将 Intent 逐一传递给 onHandleIntent()。
- 提供 onBind() 的默认实现(返回 null),再次强调 IntentService是创建启动式服务的。
- 重写其他回调方法,如 onCreate()、onStartCommand() 或 onDestroy(),请确保调用超类实现,以便 IntentService 能够妥善处理工作线程的生命周期。onBind()除外。
- onStartCommand() 必须返回默认实现(因为它将 Intent 传递给 onHandleIntent()):
7.onStartCommand() 方法必须返回整型数
整型数是一个值,用于描述系统应该如何在服务终止的情况下继续运行服务。注意:这里说服务终止,没说是手动停止的还是系统强行停止的。
- START_NOT_STICKY 系统不会重建服务
- START_STICKY 重建服务并调用 onStartCommand(),但不会重新传递最后一个 Intent。
- START_REDELIVER_INTENT 会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。注意可能会时间很长后才重启。
注意:
- 以上三个值均是在无任何挂起 Intent的前提下,如有挂起的intent,则都会重建服务并依次传递intent。
- 经测试服务运行时意外终止后,这几个返回值才有意义,如正常运行结束它们无意义,如stopself(),即使返回START_REDELIVER_INTENT 也不重启。
- 在一些自定义很多的系统上,重启可能被拒绝.
如在android7.1.1 google api x86模拟器上,按 全部清除 后即使返回重启服务的值,service也不重启了.
在华为android7.0系统,AppAutoStartupPolicy 可能阻止你的服务重新启动.
06-11 15:47:42.292 1494-13224/? I/HwPFWLogger: AppAutoStartupPolicy:prevent scheduleRestart service of package com.example.android.jobscheduler, serviceInfo com.example.android.jobscheduler.service.MyJobService
06-11 15:48:12.311 1494-1494/? I/HwPFWLogger: AppAutoStartupPolicy:prevent start package com.example.android.jobscheduler, serviceInfo com.example.android.jobscheduler.service.MyJobService by callerPid 1494, callerUid 1000, scene:jobService
在小米手机上
06-11 16:45:05.849 1432-1443/system_process I/ActivityManager: Force stopping service ServiceRecord{bf9fd5e u0 com.example.android.jobscheduler/.service.MyJobService} 06-11 16:45:06.147 1432-1447/system_process I/AutoStartManagerService: MIUILOG- Reject service :Intent { cmp=com.example.android.jobscheduler/.service.MyJobService } userId : 0 uid : 10127
8.启动服务
startService() 方法将立即返回,且 Android 系统调用服务的 onStartCommand() 方法。如果服务尚未运行,则系统会先调用 onCreate(),然后再调用 onStartCommand()。
9.启动式服务如何与启动者通信?
如果服务亦未提供绑定,则使用 startService() 传递的 Intent 是应用组件与服务之间唯一的通信模式。但是,如果您希望服务返回结果,则启动服务的客户端可以为广播创建一个 PendingIntent (使用 getBroadcast()),并通过启动服务的 Intent 传递给服务。然后,服务就可以使用广播传递结果。
10.停止服务
启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在 onStartCommand() 返回后会继续运行。因此,服务必须通过调用 stopSelf() 自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。
注意:启动的服务,在内存不足时才销毁,绑定的服务如果没有绑定者后会被销毁。
一旦服务收到对 onStartCommand() 的调用,您始终仍须亲自停止服务。即使是bind方式启动的服务。
11.关于stopSelf(int)的理解
它是在service内部停止服务的方法,参数是服务的启动id,这个id在每次onStartCommand(Intent intent, int flags, int startId)的第3参数传过来,是系统给每次启动服务分配的id。可以保存它,然后在stopSelf时用它。
使用 stopSelf(startId) 确保服务停止请求始终基于最近的启动请求。如果在您能够调用 stopSelf(startId) 之前服务收到了新的启动请求,ID 就不匹配,服务也就不会停止。
12.前台服务
前台服务被认为是必需让用户意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。前台服务必须为状态栏提供通知让用户知道正在进行xxx服务。
startForeground 请求让服务运行于前台,提供给 startForeground() 的整型 ID 不得为 0
stopForeground 从前台移除服务,注意:这个不是停止服务只是从前台移出?
13.服务生命周期
onCreate--->onStartCommand--->onBind--->onUnbind--->onRebind--->onDestroy
注:与 Activity 生命周期回调方法不同,您不需要调用这些回调方法的超类实现(直接继承Service时,非IntentService时)。