Service 是 Android 四大组件之一。是实现程序后台运行的解决方案。
默认是运行主线程中。
基本使用流程
- 自定义 Service 继承 Service() 类, 必须重写唯一抽象方法 onBind()
- 为了 完成事情逻辑的处理,一般会重写 onCreate(), onStartCommand(), onDestroy() 方法
- 在 AndroidManifest.xml 中注册
分支一:启动、停止Service
-
使用显式 Intent 绑定自定义的Service;使用startService(intent)来启动Service
-
使用显式 Intent 绑定自定义的Service;使用stopService(intent)来停止Service
分支二:Activity 和 Service 进行通信--- Bind Service 的方式,让 Service 从一个"后台默默干活"的组件,变成一个"可以被前端控制"的对象。
- 自定义 Service
-
内部创建
Binder子类,用于暴露 Service 中需要被 Activity 调用的方法。 -
重写
onBind(),返回该 Binder 实例。
- Activity 端
-
实现
ServiceConnection接口,重写onServiceConnected(绑定时调用,里面有Binder类型的参数) 和onServiceDisconnected(解绑时调用)。 -
使用显式 Intent (指定 Service 的类名)调用
bindService()。 -
在适当生命周期(如
onDestroy)调用unbindService()解绑。
Service 的生命周期
- 整体生命周期回调 :
onCreate(),onStartCommand(),onBind(),onUnbind(),onDestroy()。
启动式:
text
调用startService()方法 → onCreate() → onStartCommand() → ... → 调用stopService()/stopSelf()方法 → onDestroy()
需要注意的是,每次 startService(), onStartCommand() 都会执行,但是只有Service之前没有创建过,onCreate才会执行。
每个进程中每个Service只会存在一个实例,因此无论调用多少次 startService(),一次 stopService()/stopSelf()方法 Service 就会停止。
绑定式:
text
调用bindService()方法 → onCreate() → onBind() → ... → 调用unbindService()方法 → onUnbind() → onDestroy()
销毁条件 :所有客户端都解绑 后,Service 会立即调用 onDestroy() 销毁(前提是没有被 startService 启动过)
onBind 只调用一次(除非 Service 被销毁重建) ,当第一个客户端绑定后,后续客户端再调用 bindService,如果 Service 当前还有其他客户端连着,则没有任何生命周期回调。
-
当第一个客户端调用
bindService()时,系统会:-
检查该 Service 是否已启动(没有则调用
onCreate()) -
调用
onBind()获取IBinder对象并返回给客户端 -
将这个
IBinder缓存起来
-
-
当第二个、第三个客户端再调用
bindService()绑定同一个 Service(实例未销毁)时:-
系统直接复用之前缓存的
IBinder对象 -
不会再调用
onBind() -
新客户端直接获得那个
IBinder,可以立即与 Service 通信
-
混合式:
text
startService() → onCreate() → onStartCommand()
bindService() → onBind() (此时 Service 继续运行)
unbindService() → onUnbind() (但 Service 不会销毁,因为之前 startService 了)
stopService() → onDestroy()
只有都解绑,或者停止后,才会onDestroy()回调。
前台Service
从 Android8.0 开始,只有前台可见的情况下,Service才能稳定运行,否则可能随时被系统回收。
为了使 Service 能够一直保持运行状态,使用通知的方式,将Service一直以通知的形式在状态栏显示,即保持在前台显示,以确保系统不会回收 Service。
可以视为: Service + 通知 + 权限声明
这里不是以 manager.notify(1, notification) 来显示通知,而是在 Service 中 onCreate 使用 startForeground(1,notification) 来显示前台 Service。
此次前台Service 需要 进行权限声明
多线程使用Service
因为Service默认是运行在主线程的,而Service一般会处理一些耗时逻辑,例如下载,很容易出现ANR(Application Not Responding)。 因此需要用到多线程技术.
方式:
- 在Service的每个具体方法开启一个子线程。例如
thread{}。 - 执行完逻辑后在
thread{}中使用stopSelf()、stopService() 停止 Service 防止一直处于运行状态消耗系统资源
IntentService 是上述逻辑的一种Service封装类。