本次我们没有采取分享公众号推文的方法,我想直接这样看看效果。

本文首发于微信公众号「nanchen」,你可以直接在公众号搜索「nanchen」或者扫描最下面的二维码关注我。做不完的开源,写不完的矫情,南尘一直与你同行。

这是 面试系列 的第三期。本期我们将来探讨一下 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

Android 面试(四):Android Service 你真的能应答自如了吗?相关推荐

  1. 【Android面试】Android面试题集锦 (陆续更新)

    [Android面试]Android面试题集锦 (陆续更新) 分类: [杂七杂八]2011-05-11 17:58 2064人阅读 评论(0) 收藏 举报 一些常见的Android面试基础题做下总结, ...

  2. Android面试,与Service交互方式

    五种交互方式,分别是:通过广播交互.通过共享文件交互.通过Messenger(信使)交互.通过自定义接口交互.通过AIDL交互.(可能更多) Service与Thread的区别 Thread:Thre ...

  3. 【Android面试】Android中高级开发面试必问,7年外包一飞冲天

    Andorid 开发在前两年也非常火热,但随着客户端开发招聘回归理性,行业已经越来越成熟,岗位招聘也就自然而然地变"卷"了.这一点,身为程序员老鸟的我深有体会. 年初,我就开始投递 ...

  4. 【Android面试】Android面试题集锦 (陆续更新)(最新2012-6-18)

    1.android开发新浪面试题[开发者必看哦] 下载地址 http://www.eoeandroid.com/thread-177885-1-1.html 2.华为关于android笔试题案例解析 ...

  5. Android 面试(Android 篇)

    Android 面试 安卓篇 一.跨进程通信的几种方式 二.多进程应用使用场景 三.Binder 机制 (进程间的通信) 四.说一说 ANR 五.什么是OOM,如何避免解决 六.内存泄露,内存溢出,内 ...

  6. 【Android面试】Android面试题集锦 (陆续更新)(最新2012-6-18) eoe上看到的

    ===============eoeAndroid社区推荐:======================= 1.Android开发新浪面试题[开发者必看哦] 下载地址 http://www.eoean ...

  7. android面试经典,Android经典面试题集锦(一)

    1.描述你知道的Android机型适配方案: 答:1.Linearlayout的weiget属性:2.res目录下自定义各种不同机型尺寸的values包中的dimens.xml文件:3.今日头条开源的 ...

  8. android面试 handler,Android面试之Handler相关学习

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? ###Android面试之Handler相关学习 1.Android消息机制之Looper.java源代码学习 1). ...

  9. android面试service,Android面试,与Service交互方式(4)

    自定义接口交互 4何谓自定义接口呢,其实就是我们自己通过接口的实现来达到Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的, ...

最新文章

  1. 4 Git 基础 - 撤消操作
  2. java王者归来pdf_《JAVA WEB整合开发王者归来》刘京华.pdf
  3. easyui datagrid 表格 属性和方法
  4. 笔记-项目整体管理-开工会议-kick-off-meeting
  5. 北邮OJ 1005. 16校赛-Hawei Learning C
  6. WCF 入门 WCF基础知识问与答
  7. 容器编排技术 -- 了解Kubernetes对象
  8. 叶修手速900什么概念_什么是数学?数学是探索的过程
  9. @程序员,快来速取硬核的汇编语言知识大全!
  10. 计算机组成原理-白中英版
  11. 固高板卡mct2008调试轴回零_固高电机控制调试软件mct2008 v2.0
  12. hscan扫描mysql代码_redis 迭代命令SCAN、SSCAN、HSCAN、ZSCAN
  13. 磁盘管理之动态磁盘和静态磁盘的区别
  14. 重磅!厦门大学信息学院11篇论文入选AI顶会AAAI 2021
  15. 强化学习实践三 :编写通用的格子世界环境类
  16. 2022联想小新pro14和联想小新pro16 区别 哪个好
  17. 放弃Dubbo了,不太适合小系统
  18. 不能卸载java_java不能完全卸载了,怎么处理???跪求高手指教11
  19. 安卓小米系统开发一些适配问题
  20. matlab系统稳态误差终值,探究开环系统与闭环系统的稳态误差.docx

热门文章

  1. android 签名报错,AndroidStudio生成签名apk报错
  2. java 日志切面_自定义注解+面向切面整合的日志记录模块(一)
  3. linux搭建博客day5-安装Mysql
  4. 10分钟学会数据库压力测试
  5. c语言给定一个单链表输入k,C语言实现单链表(不带头结点)的基本操作
  6. matlab画图,想让子图使用不同的色标
  7. linux光驱安装内核,Linux的内核管理--之光盘恢复grub的方法
  8. 3复数与复变函数(三)
  9. 图片缩放与目标值的规范
  10. java环境变量设置 重启吗_java环境变量配置,原来是这样的