Android组件体系之Service解析
一、调用方式
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解析的更多相关文章
- Android组件体系之Activity启动模式解析
本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity ...
- Android组件体系之BroadcastReceiver小结
1.常见分类 BroadCastReceiver,按注册方式可以分为静态广播接收器和动态广播接收器. 静态广播接收器:不受程序是否启动的约束,当应用程序关闭之后,还是可以接收到广播(一般广 ...
- Android组件体系之视图绘制
一.View组件View组件有几个重要的方法需要关注,也是自定义View经常需要重写的方法. 1.measure作用是测量View组件的尺寸.对应的方法是onMeasure,测量View的宽和高.Vi ...
- Android组件体系之ContentProvider使用注意事项
1.数据访问机制 客户端/调用者通过getContentResolver调用,由ActivityThread.AMS获取到ContentProvider的代理,再通过这个代理对象调用服务端的实现(也即 ...
- Android组件内核之Service内核原理(三)
阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680本篇文章将先从以下三个内容来介绍Service内核原理: [startSe ...
- Android组件系列----Android Service组件深入解析
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- Android 组件之Service解析
原创文章,转载请注明 http://blog.csdn.net/leejizhou/article/details/50866875 李济洲的博客 Service是Android四大组件之中的一个.S ...
- 【Android开发精要笔记】Android组件模型解析
Android组件模型解析 Android中的Mashup 将应用切分成不同类别的组件,通过统一的定位模型和接口标准将他们整合在一起,来共同完成某项任务.在Android的Mashup模式下,每个组件 ...
- Android 四大组件之二(Service)
service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务 ...
随机推荐
- 【JAVA - 基础】之String存储机制浅析
本文主要解决以下几个问题 String源码解析? String和new String的区别? String通过"+"或concat累加时的对象创建机制? StringBuilder ...
- 【JavaEE】之MyBatis插入数据后获取自增主键
很多时候,我们都需要在插入一条数据后回过头来获取到这条数据在数据表中的自增主键,便于后续操作.针对这个问题,有两种解决方案: 先插入,后查询.我们可以先插入一条数据,然后根据插入的数据的各个字段值,再 ...
- 爬取电影top250 电影名 导演 演员 风格 国家 时长 评分 录入mySQL数据库
import requestsfrom lxml import etreeimport reimport pymysqlimport time conn = pymysql.connect(host= ...
- 第三章 学习Shader所需的数学基础(1)
1. 笛卡尔坐标系 在游戏中,我们使用的数学大部分都是为了计算位置.距离和角度等变量.而这些就算大部分是在笛卡尔坐标系下进行的. 1.1 二维笛卡尔坐标系 一个二维笛卡尔坐标系包含了两个部分的信息 1 ...
- J.U.C剖析与解读2(AQS的由来)
J.U.C剖析与解读2(AQS的由来) 前言 前面已经通过实现自定义ReentrantLock与自定义ReentrantReadWriteLock,展示了JDK是如何实现独占锁与共享锁的. 那么实际J ...
- 记录一些实用的小技巧-CSS篇
1.单行文本截断 .text{ width: 200px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } 2.多行 ...
- wow钓鱼方案
最近怀旧服启动了 玩(排)得我萎靡不堪 突然想起多年前写过一个钓鱼的按键精灵 赶紧搜出来助我一臂之力 奈何往年不知其珍贵 早不见了 千思万想才在群空间的文件夹内翻出来一个exe版本 而源代码已不知去向 ...
- 使用iCamera 测试MT9F002 1400w高分辨率摄像头小结 之!!看清细节!!!
使用iCamera 测试MT9F002 1400w高分辨率摄像头小结 之!!看清细节!!! 本方案测试两种种分辨率输出(其他更多分辨率设置,可以参考手册配置) 4608*3288=1515万像素 11 ...
- robotframework配置邮箱服务器
1.登录邮箱以腾讯企业邮箱为例:开启smtp服务并获得邮箱的客户端授权码 用户名:18890260218@163.com 客户端授权码:admin123 2.进入系统管理-->GO to plu ...
- JS-scrollTop、scrollHeight、clientTop、clientHeight、offsetTop、offsetHeight的理解
scrollTop, 可写(这些属性中唯一一个可写的元素) Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数. 一个元素的 scrollTop 值是这个元素的顶部到 ...