一、调用方式
    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. Ansible Playbooks 介绍 和 使用 一

    目录 Ansible Playbooks Playbooks 组成部分: YAML 介绍 YAML 语法 Ansible 基础元素 变量 facts registre 通过命令传递变量 通过roles ...

  2. 关于小码哥kylin

    技术格言: 用双手改变人生,用代码改变世界! 个人网站:http://www.isainttech.com QQ:56619556 Email:dragonsaint@qq.com 微信:kylin1 ...

  3. appium环境的搭建

    appium环境的搭建,之前看过很多关于appium环境搭建的文章,一个感觉就是“乱”. 所以才想自己来写一篇appium环境的搭建,算是总结和备忘吧. 如下图,其实appium的搭建分三部分完成,各 ...

  4. block的本质

    全局变量

  5. ThinkPHP 实现数据库事务回滚示例代码

    ThinkPHP提供了数据库的事务支持,如果要在应用逻辑中使用事务,可以参考下面的方法:   启动事务: $User->startTrans(); 提交事务: $User->commit( ...

  6. luogu P3807 【模板】卢卡斯定理

    求 C(n,n+m)%p C(m,n)%p=C(m%p,n%p)*C(m/p,n/p) #include<cstdio> #include<cstring> #include& ...

  7. luogu P1768 天路 |01分数规划+负环

    题目描述 言归正传,小X的梦中,他在西藏开了一家大型旅游公司,现在,他要为西藏的各个景点设计一组铁路线.但是,小X发现,来旅游的游客都很挑剔,他们乘火车在各个景点间游览,景点的趣味当然是不用说啦,关键 ...

  8. [01]Go设计模式:单例模式(Singleton)

    目录 单例模式 一.简介 二.代码实现 1.懒汉模式 2.饿汉模式 3.改进型懒汉模式 4. sync.once实现 5.测试用例 单例模式 一.简介 单例模式(Singleton Pattern)是 ...

  9. ZooKeeper初步

    ZooKeeper 简介: 顾名思义 zookeeper 就是动物园管理员,他是用来管 hadoop(大象).Hive(蜜蜂).pig(小猪)的管理员, Apache Hbase 和 Apache S ...

  10. Java并发编程系列-(5) Java并发容器

    5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ...