零、资料
- 前辈文章
- 《第一行代码》
一、简介
Android 四大组件中的计算型组件,无用户界面、在后台运行、生命周期长。
常用作提供在后台长期运行的服务,如复杂计算、音乐播放、下载等。
二、生命周期
1.生命周期图
2.外部调用方法
当在活动中调用服务时可调用如下方法。
startService()
- 启动服务
- 调用:
onCreate()
、onStartCommand()
-
流程:
stopService()
关闭服务
调用:
onDestory()
-
流程:
说明:当服务为绑定状态需先解除绑定后再调用
stopService()
关闭服务,直接调用stopService()
无法停止服务。
bindService()
- 绑定服务
- 调用:
onCreate()
、onBind()
-
流程:
- 说明:
boolean bindService(Intent service, ServiceConnection conn, int flags)
- Intent:意图
- ServiceConnection:监听服务状态
-
onServiceConnected
活动与服务成功绑定-
onServiceConnected(ComponentName name, IBinder service)
IBinder
为服务的Binder
实例,可通过此实例来进行服务的操作。调用指定服务执行响应操作。
-
-
onServiceDisconnected
活动与服务解绑
-
- 标志位:
- 官方说明
-
BIND_AUTO_CREATE
:只要绑定存在,就自动创建服务。 - ...
unbindService()
- 解绑服务
- 调用:
onUnbind()
、onDestory()
-
流程:
3.Service方法
onCreate()
- 创建服务
- 服务创建时调用,创建后不会再调用。
onStartCommand()
- 开始服务
- 说明:返回值描述了系统在杀死服务后应该如何继续运行。
- 官方说明
- START_NOT_STICKY:不重建服务(还存在未发送的intent除外)
- START_STICKY:重建服务&调用
onStartCommand()
但用null intent
来调用onStatCommand()
(还存在未发送的intent除外) 。适用于媒体播放器类似服务,它们不执行命令,但需要一直运行并随时待命) - START_REDELIVER_INTENT:重建服务&用上一个已送过的intent调用onStartCommand()。适用于那些需要立即恢复工作的活跃服务,比如下载文件。
- ...
onDestroy()
- 销毁服务
- 服务器销毁时调用。
onBind()
- 绑定服务
IBinder onBind(Intent intent)
- 用来活动与服务进行通信。
onUnbind()
- 解绑服务
stopSelf()
- 停止服务
三、其他常用方法
1.startForeground
-
startForeground(int id, Notification notification)
使后台服务变为前台服务- id:通知id
- notification:通知对象
2.stopForeground
- 从前台状态中删除此服务,此时服务并未停止。
3.配置
android:enabled=["true" | "false"]
- 是否这个服务能被系统实例化,如果能则为true,否则为false。默认为true。
android:exported=["true" | "false"]
- 是否其它应用组件能调用这个服务或交互,能为true,默认值依赖于是否包含过滤器。
android:process=["Sting"]
- 是否需要在单独的进程中运行,值为进程名称,默认主进程。
四、编写形式
1.较标准的服务
服务中的代码默认运行在主线程当中,如果直接在服务里去处理一些耗时的逻辑,就很容易出现ANR ( Application Not Responding)的情况。
我们应该在服务的每个具体的方法里开启一个子线程,然后在这里去处理那些耗时的逻辑。
-
因此,一个比较标准的服务就可写成如下形式:
public class MyService extends Service { ... @override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(() -> { // TODO 处理具体的逻辑 // 执行完立即关闭碰 // stopSelf(); }).start(); return super.onStartCommand(intent, flags, startId); } }
五、分类
1.本地 vs 远程
了解IPC
、AIDL
能更理解本地服务与远程服务。
- IPC:Inter-Process Communication,即跨进程通信。
- AIDL:Android Interface Definition Language,即Android接口定义语言。用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
本地服务(LocalService)
- 运行在主线程(节约资源)。
- 主线程被终止后,服务也会终止(限制性大)。
- 由于在同1进程因此不需
IPC
和AIDL
通信。 - 最常用的服务类型,如音乐播放。
远程服务(RemoteService)
- 运行在独立进程(消耗资源)。
- 服务常驻在后台,不受其他
Ativity
影响(灵活)。 - 使用
AIDL
进行IPC
通信复杂。 - 常作为系统级服务。
2.前台 vs 后台
前台服务
- 通知栏显示通知(用户可见)。
- 服务使用时,需让用户知道 & 进行相关操作,如音乐播放服务。(服务被终止时,通知栏的通知也会消失)。
后台服务
- 处于后台(用户无法看到)。
- 服务使用时不需要让用户知道 & 进行相关操作,如天气更新、日期同步
- 后台服务(服务被终止时,用户无法知道)。
3.不可通信 vs 可通信
不可通信的后台服务
- 用
startService()
启动,调用者退出后服务仍然存在。 - 服务不需与
Activity
&Service
通信。
可通信的后台服务
bindService() 启动:
- 用
bindService()
绑定,调用者退出后服务销毁。 - 服务需与
Activity
&Service
通信、需控制服务开始时刻。 - 节约系统资源,第一次
BindService()
时才会创建服务的实例 & 运行,当服务为远程服务(Remote Service)时效果明显。 - 服务只是公开一个远程接口,供客户端
Android
/iOS
远程调用执行方法。 -
BroadcastReceiver
也可完成需求,但若交互频綮,容易造成性能问题。且BroadcastReceiver
本身执行代码的时间非常短且可能执行到一半,后面的代码便不会执行。而服务则没有这些问题。
StartService()、bindService()启动:
- 用
StartService()
、bindService()
启动,调用者退出后服务销毁。 - 服务需与
Activity
&Service
通信、不需控制服务开始时刻(服务一开始便运行)。
六、IntentService
作用
处理异步请求 & 实现多线程,任务按顺序、在后台执行,执行后自行关闭。常用做离线下载等。
流程
本质
IntentService
= Handler
+ HandlerThread
- 通过
HandlerThread
单独开启1个工作线程:IntentService
。 - 创建1个内部
Handler
:ServiceHandler
。 - 绑定
ServiceHandler
与IntentService
。 - 通过
onStartCommand()
传递服务intent
到ServiceHandler
、依次插入Intent
到工作队列中 & 逐个发送给onHandleIntent()
。 - 通过
onHandleIntent()
依次处理所有Intent
对象所对应的任务。
因此我们通过复写onHandleIntent()
& 在里面根据Intent
的不同进行不同线程操作即可。
说明
- 多次启动
IntentService
,每个耗时操作以队列的方式在IntentService
的onHandleIntent
回调方法中依次执行,执行完自动结束。 - 工作任务队列是顺序执行的,若服务停止,则会清除消息队列中的消息,后续的事件不执行。
- 不建议通过
bindService()
启动IntentService
。在IntentService
中onBind()
默认返回null
。
项目Demo
Demo地址 中的 Service [module]
2019-11-01