service 在项目开发中会经常用到, 但是只是知道如何使用, 不懂 service 的内部实现原理, 本章带领大家清晰的理解 service 和 service 是如何工作的, 以及常见的问题
根据以下问题来学习, 效率会更高:
1 什么是 Service
2Service 的生命周期
3Service 的工作过程
4Service 的 start 和 bind 状态有什么区别?
5 同一个 Service, 先 startService, 然后再 bindService, 如何把它停止掉?
6 你有注意到 Service 的 onStartCommand 方法的返回值吗? 不同返回值有什么区别?
7Service 的生命周期方法 onCreateonStartonBind 等运行在哪个线程?
1. 什么是 service?
服务是一种应用程序组件, 表示应用程序希望在不与用户交互的情况下执行长时间运行的操作, 或者为其他应用程序提供的功能每个服务类必须在其包的 AndroidManifest.xml 中具有相应的 <service> 声明服务可以使用 Context.startService()和 Context.bindService()来启动 请注意, 与其他应用程序对象一样, 服务在主机进程的主线程中运行这意味着, 如果你的服务要做任何 CPU 密集型 (如 MP3 播放) 或阻塞 (如网络) 操作, 它应该产生自己的线程来完成这项工作有关这方面的更多信息可以在进程和线程中找到 IntentService 类可作为 Service 的标准实现提供, 它具有自己的线程, 用于调度要完成的工作
2.Service 的生命周期
Service 有两种启动方式:
调用 Context.startService(), 那么系统将检索服务 (如果需要, 创建它并调用它的 onCreate() 方法), 然后使用客户端提供的参数调用它的 onStartCommand(Intent,int,int)方法此服务将继续运行, 直到调用 Context.stopService()或 stopSelf()请注意, 对 Context.startService()的多次调用不会嵌套 (尽管它们会导致对 onStartCommand()) 进行多次相应调用), 因此无论启动多少次, 服务都会停止一次 Context.stopService()或 stopSelf () ; 然而, 服务可以使用他们的 stopSelf(int)方法来确保服务不会停止, 直到处理完启动的意图为止对于已启动的服务, 根据从 onStartCommand()返回的值, 他们可以决定运行两个额外的主要操作模式: START_STICKY 用于根据需要显式启动和停止的服务, 而使用 START_NOT_STICKY 或 START_REDELIVER_INTENT 对于在处理发送给它们的任何命令时应该只保持运行的服务
调用 Context.bindService()来获得到服务的持久连接如果服务尚未运行 (同时调用 onCreate()), 则同样会创建服务, 但不会调用 onStartCommand() 客户端将收到服务从其 onBind(Intent)方法返回的 IBinder 对象, 从而允许客户端将该服务调用回该服务只要建立连接(无论客户是否保留对服务的 IBinder 的引用), 该服务就会继续运行返回的 IBinder 通常是用于一个复杂的接口, 已经被写入 aidl
服务既可以启动, 也可以绑定连接在这种情况下, 只要系统启动, 或者存在与 Context.BIND_AUTO_CREATE 标志的一个或多个连接, 系统就会继续运行该服务一旦这些情况都不成立, 就会调用服务的 onDestroy()方法, 并且服务被有效终止从 onDestroy()返回后, 所有清理 (停止线程, 取消注册接收者) 应该完成
3.Service 的工作过程
Service 分为两种工作状态: 一种是启动状态, 主要用于执行后台计算; 另一种是绑定状态, 主要用于其他组件和 service 的交互 service 的两种状态是可以共存的, 那么 Service 既可以处于启动状态也可以处于绑定状态
启动状态:
- Intent intent = new Intent(this, MyService.class);
- startService(intent);
绑定状态:
- Intent intent = new Intent(this, MyService.class);
- bindService(intent,conn,BIND_AUTO_CREATE);
service 的启动过程
1.startService(intent);
我们看一下 service 的源码 :package android.app.Service;
public abstract class Service extends ContextWrapper implements ComponentCallbacks2
Service 继承了 ContextWrapper ,service 的启动过程是从 ContextWrapper 的 startService 开始
- @Override
- public ComponentName startService(Intent service) {
- return mBase.startService(service);
- }
通过 mBase, 调用 startService
- public class ContextWrapper extends Context {
- Context mBase;
- public ContextWrapper(Context base) {
- mBase = base;
- }
而 Context 类是个 abstract
public abstract class Context
Activity 被创建时会通过 attach 方法将一个 ContextImpl 对象关联起来, ContextImpl 实现了 Context,mBase 的类型就是 ContextImpl ,ContextWrapper 大部分操作都是通过 mBase 完成的, 这是一种典型的桥接模式
startService 是通过 Context 调用的, 那我们看下 ContextImpl 是如何实现 startService 的
- @Override
- public ComponentName startService(Intent service) {
- warnIfCallingFromSystemProcess();
- return startServiceCommon(service, mUser);
- }
- private ComponentName startServiceCommon(Intent service, UserHandle user) {
- try {
- validateServiceIntent(service);
- service.prepareToLeaveProcess(this);
- // 开启服务 ActivityManagerNative.getDefault() 其实就是 ActivityManagerService(AMS)
- ComponentName cn = ActivityManagerNative.getDefault().startService(
- mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
- getContentResolver()), getOpPackageName(), user.getIdentifier());
- if (cn != null) {
- if (cn.getPackageName().equals("!")) {
- throw new SecurityException(
- "Not allowed to start service" + service
- + "without permission" + cn.getClassName());
- } else if (cn.getPackageName().equals("!!")) {
- throw new SecurityException(
- "Unable to start service" + service
- + ":" + cn.getClassName());
- }
- }
- return cn;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
简单说一下 ActivityManagerNative
- public abstract class ActivityManagerNative extends Binder implements IActivityManager
- {
- /**
- * Cast a Binder object into an activity manager interface, generating
- * a proxy if needed.
- */
- static public IActivityManager asInterface(IBinder obj) {
- if (obj == null) {
- return null;
- }
- IActivityManager in =
- (IActivityManager)obj.queryLocalInterface(descriptor);
- if (in != null) {
- return in;
- }
- return new ActivityManagerProxy(obj);
- }
- /**
- * Retrieve the system's default/global activity manager.
- */
- static public IActivityManager getDefault() {
- return gDefault.get();
- }
- }
- private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
- protected IActivityManager create() {
- IBinder b = ServiceManager.getService("activity");
- if (false) {
- Log.v("ActivityManager", "default service binder =" + b);
- }
- IActivityManager am = asInterface(b);
- if (false) {
- Log.v("ActivityManager", "default service =" + am);
- }
- return am;
- }
- };
- public final class ActivityManagerService extends ActivityManagerNative
ActivityManagerService 是继承 ActivityManagerNative 的 AMS 启动服务是一个远程调用过程, 更具体的实现过程大家可以看源码, 这里就不在长篇幅的写源码的启动过程了
2.bindService 的绑定过程同样在 ContextImpl 中, 大家可自行翻阅理解
4.Service 的 start 和 bind 状态有什么区别?
start 启动的 service, 不依赖组件, 有独立的生命周期, 多次调用 service 不会嵌套, 尽管会对 onStartCommand()多次调用, 因此无论启动多少次, 服务都会停止一次 Context.stopService()或 stopSelf ()(IntentService 会自动调用一次 onStopSelf). 然而, 服务可以使用他们的 stopSelf(int)方法来确保服务不会停止, 直到处理完启动的意图为止对于已启动的服务, 根据从 onStartCommand()返回的值, 他们可以决定运行两个额外的主要操作模式: START_STICKY 用于根据需要显式启动和停止的服务, 而使用 START_NOT_STICKY 或 START_REDELIVER_INTENT 对于在处理发送给它们的任何命令时应该只保持运行的服务
bind 绑定的 service 依赖于组件, 组件销毁 service 也随之销毁, 需要注意的比如在 Activity 中 bind 了 service, 那么必须在 onDestory 方法中销毁 service 调用 unBindServie 方法多次调用 bind 方法只会调用一次 onBind()方法, 但不会调用 onStartCommand()停止服务是调用了 n 次 bindService, 就必须要调用 n 次 unBindService.
5. 同一个 Service, 先 startService, 然后再 bindService, 如何把它停止掉?
startService 不论调用几次, 只需要 stopService(或 stopSelf) 一次即可停止掉服务
如果调用了 n 次 bindService, 必须调用 n 次 unBindService 方法, 才能停止掉服务
执行的顺序没有要求
最后一个 stopService(或 stopSelf)或者 unBindService 方法会导致 Service 的 onDestroy 方法执行
6. Service 的 onStartCommand 方法的返回值? 不同返回值有什么区别?
一共有四种返回值
- START_STICKY_COMPATIBILITY,
- START_STICKY,
- START_NOT_STICKY,
- START_REDELIVER_INTENT,
- /**
- * 不保证的 {@link #START_STICKY} 版本
- * {@link #onStartCommand}在被杀后会再次被调用
- * 为了兼容版本, 在 service 被杀死后, 并不保证 onStartCommand 会被再次调用
- */
- public static final int START_STICKY_COMPATIBILITY = 0;
- /**
- * 如果此 service 是进程在启动时被杀死(返回后), 保持启动状态, 但不保留 Intent , 之后系统会尝试重启该 service, 并重新回调 onStartCommand 方法, 如果没有其他的 start 命令, 会传递给 service 的 intent 为 null, 需要注意 onStartCommand 方法对 intent 的非空判断
- */
- public static final int START_STICKY = 1;
- /**
- * 常规操作, 除非死之前还有组件调用 startService, 否则系统不会保留启动状态并重启该 service
- */
- public static final int START_NOT_STICKY = 2;
- /**
- * service 被杀死后, 系统会组织一次 service 重启 (除非之前调用了 stopSelf) 被杀死之前最后一次传递的 intent 将被执行, 该 flag 将不会传递空 intent, 这适用于那些应该立即恢复正在执行的工作的服务, 如下载文件
- */
- public static final int START_REDELIVER_INTENT = 3;
7.Service 的生命周期方法 onCreateonStartonBind 等运行在哪个线程?
Service 默认是运行在主线程的, 并且其生命周期也是运行在主线程的, 所以要想在 service 中执行耗时操作必须另起一个 Thread 线程(或者使用 IntentService), 否则会 ANR.
- E/MyService: onCreate: Thread[main,5,main]
- E/MyService: onStartCommand: Thread[main,5,main]
来源: http://www.jianshu.com/p/087415add7a5