Service 系列一共 2 篇, 主要介绍 Service 相关的使用, 以及使用 Service 实现 IPC 通信. 本文的重点是介绍 Service 相关的使用, 通过 Service 实现 IPC 通信放在下一篇讲解.
What is a Service
根据官方的介绍:
Service 既不是一个线程, Service 通常运行在当成宿主进程的主线程中, 所以在 Service 中进行一些耗时操作就需要在 Service 内部开启线程去操作, 否则会引发 ANR 异常.
也不是一个单独的进程. 除非在清单文件中声明时指定进程名, 否则 Service 所在进程就是 application 所在进程.
Service 存在的目的有 2 个:
告诉系统, 当前程序需要在后台做一些处理. 这意味着, Service 可以不需要 UI 就在后台运行, 不用管开启它的页面是否被销毁, 只要进程还在就可以在后台运行. 可以通过 startService()方式调用, 这里需要注意, 除非 Service 手动调用 stopService()或者 Service 内部主动调用了 stopSelf(), 否则 Service 一直运行.
程序通过 Service 对外开放某些操作. 通过 bindService()方式与 Service 调用, 长期连接和交互, Service 生命周期和其绑定的组件相关.
- Service Lifecycle
- public class MyService extends Service {
- @Override
- public void onCreate() {
- super.onCreate();
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- return startCommandReturnId;
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- }
要解释这个首先要知道 Service 的实现, 需要实现抽象方法 onBind, 以及重写 onStartCommand, 这 2 个方法会在下文介绍到.
通过上面的介绍可以知道, Service 有 3 种启动方式:
- startService()
- bindService()
同时调用
这几种方式启动的 Service 生命周期略微不同.
startService 方式
startService()只要一个 Intent 参数, 指定要开启的 Service 即可
Intent intent = new Intent(MainActivity.this, MyService.class);
当调用 Service 的 startService()后,
Service 首次启动, 则先调用 onCreate(), 在调用 onStartCommand()
Service 已经启动, 则直接调用 onStartCommand()
当调用 stopSelf()或者 stopService()后, 会执行 onDestroy(), 代表 Service 生命周期结束.
startService 方式启动 Service 不会调用到 onBind(). startService 可以多次调用, 每次调用都会执行 onStartCommand(). 不管调用多少次 startService, 只需要调用一次 stopService 就结束. 如果 startService 后没有调用 stopSelf 或者 stopService, 则 Service 一直存活并运行在后台.
onStartCommand 的返回值一共有 3 种
START_STICKY = 1:service 所在进程被 kill 之后, 系统会保留 service 状态为开始状态. 系统尝试重启 service, 当服务被再次启动, 传递过来的 intent 可能为 null, 需要注意.
START_NOT_STICKY = 2:service 所在进程被 kill 之后, 系统不再重启服务
START_REDELIVER_INTENT = 3: 系统自动重启 service, 并传递之前的 intent
默认返回 START_STICKY;
bindService 方式
通过 bindService 绑定 Service 相对 startService 方式要复杂一点. 由于 bindService 是异步执行的, 所以需要额外构建一个 ServiceConnection 对象用与接收 bindService 的状态, 同时还要指定 bindService 的类型.
- //1\. 定义用于通信的对象, 在 Service 的 onBind()中返回的对象.
- public class MyBind extends Binder {
- public int mProcessId;
- }
- //2\. 定义用于接收状体的 ServiceConnection
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- // 和服务绑定成功后, 服务会回调该方法
- // 服务异常中断后重启, 也会重新调用改方法
- MyService.MyBind myBinder = (MyService.MyBind) service;
- }
- @Override
- public void onNullBinding(ComponentName name) {
- //Service 的 onBind()返回 null 时将会调用这个方法, 并不会调用 onServiceConnected()
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // 当服务异常终止时会调用.
- // 注意, unbindService 时不会调用
- }
- };
- //3\. 在需要的地方绑定到 Service
- bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
bindService()也可以调用多次, 与 startService()不同, 当发起对象与 Service 已经成功绑定后, 不会多次返回 ServiceConnection 中的回调方法.
通过 bindService 方式与 Service 进行绑定后, 当没有对象与 Service 绑定后, Service 生命周期结束, 这个过程包括绑定对象被销毁, 或者主动掉调用 unbindService()
startService 和 bindService 同时开启
当同时调用 startService 和 bindService 后, 需要分别调用 stopService 和 unbindService,Service 才会走 onDestroy()
一个 Service 必须要在既没有和任何 Activity 关联又处理停止状态的时候才会被销毁.
IntentService
通过上面的介绍我们知道, 通过 StartService 形式开启 Service 时, 如果不主动调用 stopService,Service 将在后台一直运行. 同时如果我们在 Service 中执行耗时操作还是引起 ANR 异常, 为了解决这 2 个问题, IntentService 出现了. 当我们需要执行某些一次性, 异步的操作时, IntentService 能很好的满足这个场景.
IntentService 相比于普通的 Service, 在使用时将不再需要实现 onStartCommand(), 同时需要实现 onHandleIntent(). 真正需要我们处理的逻辑就在 onHandleIntent()实现, IntentService 会内部自动调用 stopSelf()关闭自己.
至于防止 ANR 异常, 具体的实现方式其实还是挺简单, 就是在内部新建了子线程, 并在子线程中内部的 Looper 来分发事件, 具体代码就不贴了.
下一篇 Android Service 详解 (二) 将介绍通过 Service 实现 IPC 通信
[附] 相关架构及资料
image
资料领取
点赞 + 加群免费获取 Android IoC 架构设计
加群领取获取往期 Android 高级架构资料, 源码, 笔记, 视频. 高级 UI, 性能优化, 架构师课程, NDK, 混合式开发 (ReactNative+Weex) 微信小程序, Flutter 全方面的 Android 进阶实践技术, 群内还有技术大牛一起讨论交流解决问题.
来源: http://www.jianshu.com/p/9dd439b6d64d