这是 面试系列 的第三期。本期我们将来探讨一下 Android 四大组件的重要组成部分:Service。

往期内容传递:
Android 面试(一):说说 Android 的四种启动模式
Android 面试(二):如何理解 Activity 的生命周期
Android 面试(三):用广播 BroadcastReceiver 更新 UI 界面真的好吗?

Service 有多重要?

之前在「兰柳学」的文章中看到这样一个场景,挺有意思的,先给大家分享一下,让我们一起来看看对 Service 的无知到底会有多麻烦。

场景:如果一个应用要从网络上下载一个文件,并在 Activity 上展示进度条,这个 Activity 要求是可以转屏的。那么在转屏时 Actvitiy 会重启,如何保证下载的进度条能正确展示进度呢?

不会 Service 的人,一般会想出来这样的方案。

    1. 在转屏前将进度缓存,转屏后再读出来。
    1. 使用 android:configChanges 设置,让转屏时 Activity 不销毁和重建。

针对第 1 种方案,其实细想漏洞百出。首先,转屏的过程中,我们知道 Activity 的重建算是比较耗时的,可能会有几百毫秒甚至更久,这时候下载线程仍然在工作,进度肯定和保存时的进度不一致了,如何处理这个问题呢?

第 2 个方案,大家可以自己展开思考,实际的项目中可能会需要额外做一些事情来处理 ContentView 的横竖布局的问题。

如果采用 Service,你有什么好主意呢?不妨在评论区给出。

一定听过 Service 吧,它有几种启动方式?

Service 是一个专门在后台执行长时间操作的类,它并不与用户产生 UI 交互。它提供了两种启动方式。

  • started
    其它组件调用 startService() 启动一个 Service。一旦启动,Service 将一直运行在后台,即使启动这个 Service 的组件已经被销毁。通常一个被 start 的 Service 会在后台执行单独的操作,也并不需要给启动它的组件返回结果。只有当 Service 自己调用 stopSelf() 或者其它组件调用 stopService() 才会终止。
  • bind
    其它组件可以调用 bindService() 来绑定一个 Service。这种方式会让 Service 和启动它的组件绑定在一起,当启动它的组件销毁的时候,Service 也会自动进行 unBind 操作。同一个 Service 可以被多个组件绑定,只有所有绑定它的组件都进行了 unBind 操作,这个 Service 才会被销毁。

当然,Service 还可以同时在上述两种方式下运行。这涉及到 Service 的两个回调方法的执行: onStartCommand()(通过 start 方式启动一个 Service 时的回调方法。)、onBind() (通过 bind 方式启动一个 Service 回调的方法)。

无论通过那种方式启动 Service(start、bind、start & bind),任何组件(甚至其他应用的组件)都可以使用 Service。并通过 Intent 传递参数。当然,你也可以将 Service 在 AndroidMenifest.xml 文件中配置成私有的,不允许其他应用访问。

android:exported 属性设为 false,表示不允许其他应用程序启动本应用的组件,即便是显式 Intent 也不行(even when using an explicit intent)。这可以防止其他应用程序启动您的 Service 组件。

Service 的生命周期

一谈到组件,我们总是喜欢去研究它的生命周期,而这时候用图来展示肯定是最好的了。

nanchen.png
这两条路径并不是毫不相干的。当调用 startService() 去 start 一个 Service 后,你仍然可以 bind 这个 Service。比如:当播放音乐的时候,需要调用 startService() 启动指定的音乐,当需要获取该音乐的播放进度的时候,又需要调用 bindService(),在这种情况下,除非 Service 被 unbind,此前调用 stopService()stopSelf() 都不能停止该 Service。

这些生命周期方法在使用的时候并不需要调用各自的父类方法。

两条生命周期路径都可以包含两个嵌套的生命周期:

  • 完整生命周期(entire lifetime):从 onCreate() 被调用,到 onDestroy() 返回。和 Activity 类似,一般在 onCreate() 方法中做一些初始化的工作,在 onDestroy() 中做一些资源释放的工作。如,若 Service 在后台播放一个音乐,就需要在 onCreate() 方法中开启一个线程启动音乐,并在 onDestroy() 中结束线程。

  • 活动生命周期(activity lifetime):从 onStartCommand()onBind() 回调开始,由相应的 startService()bindService() 调用。start 方式的活动生命周期结束就意味着完整证明周期的结束,而 bind 方式,当 onUnbind() 返回后,Service 的活动生命周期结束。

值得注意的是,无论是 startService() 还是 bindService() 启动 Service,onCreate()onDestroy() 均会被回调。

Service 的 onCreate() 可以执行耗时操作吗?

Service 运行在主线程中,它并不是一个新的线程,也不是新的进程,所以并不能执行耗时操作。

那如果要在 Service 中执行耗时操作,怎么做?

我想基本所有人都能想到使用 Thread,事实上我们也经常这么做。需要在主线程执行耗时操作,无非就是开一个线程,然后一阵混沌操作。当然,你还可以使用 AysncTaskHandlerThread 来替代 Thread 创建线程。

当然没有问题,那还有其它更有意思的方式吗?

有,当然有,IntentService 就是一个不错的选择。

纷繁复杂的 IntentService

nanchen.png

IntentService 继承于 Service,若 Service 不需要同时处理多个请求,那么使用 IntentService 将是最好选择。你只需要重写 onHandleIntent() 方法,该方法接收一个回调的 Intent 参数,你可以在方法内进行耗时操作,因为它默认开启了一个子线程,操作执行完成后也无需手动调用 stopSelf() 方法,onHandleIntent() 将会自动调用该方法。

使用 IntentService 的要点如下:

  • 默认在子线程中处理回传到 onStartCommand() 方法中的 Intent;
  • 在重写的 onHandleIntent() 方法中处理按时间排序的 Intent 队列,所以不用担心多线程(multi-threading)带来的问题。
  • 当所有请求处理完成后,自动停止 Service,无需手动调用 stopSelf() 方法;
  • 默认实现了 onBind() 方法,并返回 null;
  • 默认实现了 onStartCommand() 方法,并将回传的 Intent 以序列的形式发送给 onHandleIntent(),您只需重写该方法并处理 Intent 即可。

小结

当我们知道了 Service 的用途,心中有一个 Service 相关的概念时,针对实际的场景还是要做具体的分析再决定是否使用 Service。因为 Service 仍然是在主线程中调用,还是要开线程才能处理长时间的工作,Service 和 UI 的交互也让这个方式变得不那么简便。如果你只需要在当前界面去做一些耗时操作,界面退出或改变时,工作也要停止,那么这时直接使用 Thread(或者 AsyncTask, ThreadHandler)会更合适你。

做不完的开源,写不完的矫情。欢迎扫描下方二维码或者公众号搜索「nanchen」关注我的微信公众号,目前多运营 Android ,尽自己所能为你提升。如果你喜欢,为我点赞分享吧~


nanchen

更多相关文章

  1. Android统一处理断网
  2. Android应用程序的默认最大内存值以及修改
  3. JAVA与Android(安卓)世界级序列化危机与应对方案
  4. Android(安卓)Jetpack 使用入门
  5. MTK Android(安卓)紧急号码修改
  6. Android(安卓)如何实现带滚动条的TextView,在更新文字时自动滚动
  7. activity和service之间的相互通信方法
  8. Android(安卓)Handler,Looper,MessageQueue关系(讲解比较透彻的)
  9. Android(安卓)setTag方法的key问题

随机推荐

  1. Android 简单欢迎页面设计
  2. 查看Android ADT Plugin版本的方法
  3. 修改Android Studio编码格式
  4. Android打开通讯录并获取数据
  5. Android Studio Error : Instant Run req
  6. 在Android中实现全屏显示的方法
  7. Mac完整卸载Android Studio的方法
  8. 【Android 设计】:模式_ Android新特性
  9. ListView的一些属性
  10. android adb bundle下载