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卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务 ...
随机推荐
- Python使用百度地图API根据地名获取相应经纬度
今天有个需求,要根据地名获取经纬度坐标值. 于是我第一想法:打开百度地图,手动输入地名,获取.显然当地名较少时,可实施.然而,当地名较多时,此方法显然工作量很大. 于是,第二想法:代码获取,请求百度地 ...
- 阿里P7整理“硬核”面试文档:Java基础+数据库+算法+框架技术等
现在的程序员越来越多,大部分的程序员都想着自己能够进入大厂工作,但每个人的能力都是有差距的,所以并不是人人都能跨进BATJ.即使如此,但身在职场的我们一刻也不能懈怠,既然对BATJ好奇,那么就要朝这个 ...
- 洛谷P2085——最小函数值
题目描述 有n个函数,分别为\(F_1,F_2,...,F_n\).定义\(F_i(x)=A_i*x^2+B_i*x+C_i (x∈N*)\).给定这些\(A_i.B_i和C_i\),请求出所有函数的 ...
- 重磅!华为云社区·CSDN【寻找黑马程序员】有奖征文活动奖项公布!!
华为云社区·CSDN[寻找黑马程序员]第一期有奖征文活动在大家的鼎力支持下顺利落幕啦,非常感谢大家一直以来的支持~现在小宅就要隆重公布本次活动的奖项了!! 请各位获奖的伙伴在8月18日前私信联系提供联 ...
- Reactive(1) 从响应式编程到"好莱坞"
目录 概念 面向流设计 异步化 响应式宣言 参考文档 概念 Reactive Programming(响应式编程)已经不是一个新东西了. 关于 Reactive 其实是一个泛化的概念,由于很抽象,一些 ...
- JavaScript的DOM对象和jQuery对象的对比
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- nginx的部署及配置文件的介绍 域名 用户认证 SSL加密模块
步骤一:构建Nginx服务器 yum -y install gcc pcre-devel openssl-devel #安装依赖包 wget http://nginx.org/dow ...
- iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数
转自:http://www.cnblogs.com/wengzilin/p/4365855.html 本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解 ...
- Java修炼——容器HashMap用法
直接上代码,容器集合之间的关系在后面我会继续详细分析,这次先看HashMap用法 HashMap的方法都在代码中有解释.有需要的可以仔细看看 package com.bjsxt.map; import ...
- Java修炼——冒泡排序
核心思想: 1)如有一个数列有 N(5)个元素,则至多需要 N-1(4)趟循环 才能保证数列有序 2) 每一趟循环都从数列的第一个元素开始比较,依次比较 相邻的两个元素,比较到数列的最后 3) 如果前 ...