Android Service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件,它分为两种工作状态,一种是启动状态,主要用于执行后台计算;另一种是绑定状态,主要用于其他组件和Service的交互。需要注意的两点:
- 两种状态是共存的,即Service可以是启动状态也可以同时是绑定状态
- 防止ANR风险,主线程运行的Service在执行耗时操作,则应在服务内创建新线程来完成这项工作,这可以降低发生“应用无响应”(ANR) 错误的风险。
使用
要创建服务,您必须创建 Service 的子类。在实现中,需要重写一些回调方法,以处理服务生命周期的某些关键方面并提供一种机制将组件绑定到服务。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Service需要重写重要的回调方法有以下几个
- onStartCommand():通过调用 startService() 请求启动服务时,系统将调用此方法,bindService无需实现该方法
- onBind():通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法,通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信
- onCreate():首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)
- onDestroy():当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用
像Activity(以及其他组件)一样,您必须在应用AndroidManifest.xml清单文件中声明所有服务
<service android:name=".MyService"/>
通过Context启动一个Service,这会导致对 onStartCommand() 的调用,则服务将一直运行,直到服务使用 stopSelf() 自行停止运行,或由其他组件通过调用 stopService() 停止,如下所示
startService(new Intent(this, MyService.class));
但在Android8.0的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException。 新的 Context.startForegroundService() 函数将启动一个前台服务。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
并且在在service里再调用startForeground方法,不然就会出现ANR
context.startForeground(SERVICE_ID, builder.getNotification());
通过Context绑定一个Service,且未调用 onStartCommand(),则服务只会在该组件与其绑定时运行,一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它,如下所示
bindService(new Intent(this, MyService.class), connection, BIND_AUTO_CREATE);
注意:系统内存不足时,Android会强制停止优先级低的Service来提供内存给Activity使用,但持有Activity的Service可能不会终止,或者前台运行的Service几乎永远不会终止。
Service启动
首先我们先看下Service的类的调用流程
相关类说明
- ContextWrapper:代理Context的实现,简单地将其所有调用委托给另一个Context
- ContextImpl:Context API的通用实现,为Activity和其他应用程序组件提供基本上下文对象
- ActivityManager:此类提供有关活动,服务和包含过程的信息和交互
- IActivityManager.aidl:用于与ActivityManagerService交谈的系统专用API,提供了从应用程序返回到活动管理器的调用
- ActivityManagerService:负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作
- ActivityThread:管理应用程序进程中主线程的执行,根据ActivityManager请求调度和执行Activitys、broadcasts和其他操作
- ApplicationThread:ActivityThread内部类,IApplicationThread.aidl的具体实现,提供给ActivityManager,ActivityManager通过它告知应用程序将要做的事
- IApplicationThread:用于与应用程序通信的系统专用API
Service最终创建需要需要通过Handler进行消息发送来实现创建,并把创建好的servic存储在ArrayMap中。接下来看下Service的生命周期是怎样的。
需要注意的是,在整个生命周期内,只有startCommand()能被多次调用。其他方法只能被调用一次。
Service绑定
Service绑定跟Service的启动了类调用流程基本一致,只是相关方法改为bind,但其最后会调用ServiceConnection对象的onServiceConnected方法。接下来看下Service的生命周期是怎样的
但其有一个特性,多次绑定同一个Service时,Service的onBind方法只会执行一次,除非Service被终止了。