一、调用方式
    1、启动服务
    只启动一个服务,不进行通信,包括startService、startForegroundService两种调用方式。第二种方式适用于后台应用启动前台服务,在启动后的10s内(具体时间由ActiveServices.SERVICE_START_FOREGROUND_TIMEOUT定义),需要Service调用startForeground启动一个Notification,不然会出现ANR。
    整个启动流程基于ActivityManagerProxy、ActiveServices、AMS以及ActivityThread完成,两种调用方式对应的流程主要是ContextImpl.startServiceCommon方法的requireForeground参数不同。
    停止服务使用stopService方法,服务被停止的时候,系统自动回调onDestory,注意服务只会被停止一次。
    调用startService之后,Service组件的生命周期:onCreate -> onStartCommand-> onDestory。    如果服务已经启动,startService方法不会重复执行 onCreate,而是执行onStartCommand(该函数会调用onStart,保持兼容)。

2、绑定服务
    具体通过bindService调用完成,其特点是可以与服务端通信,调用服务里面的方法(本地或远程)。绑定服务的过程,通过ContextImpl、LoadedApk、ActivityThread、AMS以及ActiveServices完成。
    绑定过程中,系统会通过ActivityThread.handleBindService方法回调Service组件的onBind方法,而Service组件在这里需要返回一个IBinder实例对象给客户端调用。如果是对跨进程服务的绑定,客户端在onServiceConnected回调获得的IBinder类型的service入参是BinderProxy实例,如果是同一进程,则service是个Binder实例。
    不再需要服务时,调用者必须通过unbindService方法解除绑定,避免ServiceConnection对象导致的内存泄漏。调用者被销毁时,Service也会退出。如果是多个Activity绑定一个Service,则在最后绑定的Activity销毁之后,onUnbind才会被调用。
    生命周期:onCreate -> onBind-> onUnbind->onDestory。    绑定服务不会调用onStartCommand方法,如果服务已经绑定,bindService方法不会重复执行onBind。

3、启动+绑定
   这种特点是,可以保证服务长期后台运行,又可以调用服务里面的方法,也能和服务之间传递数据。
具体可以先startService也可以先bindService,生命周期顺序有差异。在停止服务时,需要同时调用stopService与unbindService方法。
    如果先执行stopService,则unbindService方法会使得系统依次回调onUnbind和onDestroy方法;反之,如果先执行unbindService,则unbindService方法只会调用onUnbind,然后在stopService时,回调onDestroy方法。
    这种方式启动的服务生命周期分为两种:
    先start后bind:onCreate -> onStartCommand -> onBind。
    先bind后start:onCreate -> onBind -> onStartCommand。

二、 常见服务分类
    1、本地服务
    依附在主进程上而不是独立的进程,不需要IPC,也不需要AIDL。如果是支持绑定的本地服务,只需实现onBind并返回一个实现 IBinder 接口的对象(通常是Binder派生类)。

2、远程服务
    使用独立的进程,对应进程名格式为所在包名加上指定的android:process字符串。调用者所在进程被杀,该服务依然在运行。

一般需要使用AIDL进行IPC,主要步骤包括:
1)客户端(调用端)定义远程服务对应的aidl文件。
2)在服务端的Service中定义一个IxxService.Stub实例对象,扩展实现具体业务逻辑的方法(类名IxxService及其接口必须和aidl文件中的定义一致)。
3)服务端的Service中的onBind方法,返回上述Stub实例对象。
4)客户端创建一个ServiceConnection对象,并重写onServiceConnected和onServiceDisconnected方法。在onServiceConnected方法中通过IxxService.Stub.asInterface获取Proxy代理对象(IxxService类型)。
5)客户端通过bindService启动并绑定远程服务,具体需要传入ServiceConnection对象,通过该实例完成绑定,触发回调。
6)客户端可以通过代理对象调用远程服务的各项功能;在销毁时调用unbindService解除绑定。
注意,如果aidl文件中需要访问自定义类型例如MyData(必须实现了parcelable 接口),可以新增一个aidl文件,声明自定义类,parcelable MyData; 并在调用该类的aidl文件中,导入这个类。

思考:如何实现客户端和服务端AIDL双向通信?
    首先,定义两个aidl文件,例如IMyInterface、IMyListener,分别用于提供客户端调用、给服务端回调(这两个aidl文件会同步应用到客户端和服务端)。
    其次,在IMyListener.aidl中,定义一个回调接口IMyListener,及回调方法onCallBack(); 在IMyInterface.aidl中定义接口IMyInterface以及registerCallback(IMyListener iListener)方法。
    最后,在客户端,创建一个实现IMyListener接口的对象IMyListener.Stub,再通过aidl调用服务端的registerCallback方法、传入IMyListener对象;这样在服务端就可以通过其代理(实现了IMyListener接口的对象,实际上是IMyListener.Stub.Proxy),执行回调。    这里关键是通过一个Listener对象,对应扩展aidl与注册方法,由客户端注册并传入该对象。在服务端通过这个Listener的代理执行回调接口、实现反向通信。对于这类的Listener,有时候需要使用RemoteCallbackList来辅助管理。

3、系统服务
    一种特殊的系统级的服务,例如AMS、WMS等,这些服务不属于Service组件的范畴,而是由ServiceManager统一管理、启动。这些系统服务也实现了AIDL通信机制,例如AMS,直接派生于IActivityManager.Stub。
    用户访问这些服务时,同样需要aidl文件,需要先通过ServiceManager.getService方法,获取到对应的IBinder实例,再利用Stub的asInterface方法获取Proxy对象,进而调用具体的功能实现。
    每个系统服务有个不同的name,通过ServiceManager的getService获取IBinder对象时用到。
    在系统服务内部,往往会有个内部类Lifecycle(派生于SystemService),提供给调用者(SystemServer)启动服务。实际上只是调用了Lifecycle.onStart方法,之后的具体实现流程各有不同。

(相关完整且成体系的文章可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)

Android组件体系之Service解析的更多相关文章

  1. Android组件体系之Activity启动模式解析

    本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity ...

  2. Android组件体系之BroadcastReceiver小结

    1.常见分类    BroadCastReceiver,按注册方式可以分为静态广播接收器和动态广播接收器.    静态广播接收器:不受程序是否启动的约束,当应用程序关闭之后,还是可以接收到广播(一般广 ...

  3. Android组件体系之视图绘制

    一.View组件View组件有几个重要的方法需要关注,也是自定义View经常需要重写的方法. 1.measure作用是测量View组件的尺寸.对应的方法是onMeasure,测量View的宽和高.Vi ...

  4. Android组件体系之ContentProvider使用注意事项

    1.数据访问机制 客户端/调用者通过getContentResolver调用,由ActivityThread.AMS获取到ContentProvider的代理,再通过这个代理对象调用服务端的实现(也即 ...

  5. Android组件内核之Service内核原理(三)

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680本篇文章将先从以下三个内容来介绍Service内核原理: [startSe ...

  6. Android组件系列----Android Service组件深入解析

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  7. Android 组件之Service解析

    原创文章,转载请注明 http://blog.csdn.net/leejizhou/article/details/50866875 李济洲的博客 Service是Android四大组件之中的一个.S ...

  8. 【Android开发精要笔记】Android组件模型解析

    Android组件模型解析 Android中的Mashup 将应用切分成不同类别的组件,通过统一的定位模型和接口标准将他们整合在一起,来共同完成某项任务.在Android的Mashup模式下,每个组件 ...

  9. Android 四大组件之二(Service)

    service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务 ...

随机推荐

  1. PHP通用分页类

    Page.class.php <?php/** * 分页类 * * 调用方式: * $p=new Page(总条数,显示页数,当前页码,每页显示条数,[链接]); * print_r($p-&g ...

  2. 系统目录结构、ls命令、文件类型、alias命令 使用介绍

    1周第5次课(3月23日) 课程内容: 2.1/2.2 系统目录结构2.3 ls命令2.4 文件类型2.5 alias命令 Linux系统目录结构 在Linux系统里面也是同样存在很多文件和文件夹,而 ...

  3. c语言作业07

    问题 答案 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2/homework/8655 我在 ...

  4. block的本质

    全局变量

  5. @PathVariable 处理参数为空的情况

    @RequestMapping(value = "/get/{id}/{userId}", method = RequestMethod.GET) public Result ge ...

  6. PAT甲级专题|链表

    PAT链表专题 关于PAT甲级的链表问题,主要内容 就是"建立链表" 所以第一步学会模拟链表,pat又不卡时间,这里用vector + 结构体,更简洁 模拟链表的普遍代码 cons ...

  7. ASP.NET Core 选项模式源码学习Options Configure(一)

    前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户 ...

  8. Unity 3D中C#的性能优化小陷阱

    本篇内容主要来自Unity官方手册: 一般性能优化 一些地方为本人瞎编杜撰,请酌情参考.如有错误,欢迎指出. Unity里C#编程虽然既简单还很爽,但是性能小陷阱还不少.我总强迫自己让代码最优,因此很 ...

  9. JDBC技术对数据库进行操作

    什么是 JDBC: • JDBC(Java DataBase Connectivity)java 数据库连接 • 是 JavaEE 平台下的技术规范 • 定义了在 Java 语言中连接数据,执行 SQ ...

  10. WebAPI测试概念及postman初识

    什么是接口?   ------   某个对象和外界交互的部分 消息交互接口:基于soap的web service  ---- http协议 web api   ------- http协议 diame ...