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内存区域,jvm内存各个区域详解
一.运行时数据区域 1.如图所示,可分为如下几个区域. 2.程序计数器 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.字节码解释器工作时就是通过改变这个计数器的 ...
- < AlexNet - 论文研读个人笔记 >
Alexnet - 论文研读个人笔记 一.论文架构 摘要: 简要说明了获得成绩.网络架构.技巧特点 1.introduction 领域方向概述 前人模型成绩 本文具体贡献 2.The Dataset ...
- python模块2
python模块2 相关概念 模块名是标识符(需要按照标识符的写法编写) Pyc文件 在使用模块的项目中会生成一个_pycache_文件,里面存放着编译过的(模块的)字节码缓存文件(因为模块一般很少有 ...
- shell特殊符号及cut、sort_wc_uniq、tee_tr_split命令 使用介绍
第6周第2次课(4月24日) 课程内容: 8.10 shell特殊符号cut命令8.11 sort_wc_uniq命令8.12 tee_tr_split命令8.13 shell特殊符号下 扩展1. s ...
- 限定某个目录禁止解析php、限制user_agent、php相关配置
6月1日任务 11.28 限定某个目录禁止解析php11.29 限制user_agent11.30/11.31 php相关配置扩展apache开启压缩 http://ask.apelearn.com/ ...
- PAT(甲级)2019年秋季考试
第一题用搜索,超时了,待补 更新第一题思路 dfs + 剪枝,首先确定 n的最后一位数字肯定是9,为什么呢,因为 任意两个相邻的数肯定互为质数(gcd=1),所以 n 的末尾肯定是9,这样n+1产生的 ...
- 第二周选做(myod)
02.第二周myod(选做) 实验要求: 复习c文件处理内容 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能 main与其他分开,制作静态库和动态库 编写Mak ...
- C#中的委托和事件(二)
引言 如果你看过了 C#中的委托和事件 一文,我想你对委托和事件已经有了一个基本的认识.但那些远不是委托和事件的全部内容,还有很多的地方没有涉及.本文将讨论委托和事件一些更为细节的问题,包括一些大家常 ...
- 【nodejs原理&源码赏析(3)】欣赏手术级的原型链加工艺术
[摘要] 学习经典代码中的prototype加工 示例代码托管在:http://www.github.com/dashnowords/blogs 好的代码都差不多,烂的代码却各有各的烂法. 一. 概述 ...
- MySql CPU彪高到百分之1000的排查思路
You need to enable JavaScript to run this app. 原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等情况,可查看当前链接:https:// ...