android四大组件之一——Service

目录

一、Service概述

二、生命周期 

三、权限

四、进程生命周期

五、组件与绑定Service的通信方式

1.扩展 Binder 类

2.Messenger信使

3.AIDL

七、总结

场景使用区别


一、Service概述

Service 是应用组件,代表一个应用的长时间后台运行的操作,没有交互界面,提供给其他应用一些功能。每个service类必须在清单文件AndroidManifest.xml里做 <service>声明. Services可以被启动通过Context.startService() 和Context.bindService().

services像其他应用对象一样,运行在宿主进程的主线程。这意味着,如果你的服务要执行任何CPU密集型(如MP3播放)或阻塞(如网络)操作,它应该生成自己的线程来完成这项工作。有在Processes and Threads中可以找到更多的信息。 JobIntentService 类作为标准实现类,它有自己的线程可以按部就班的处理事务。

Service 是 应用组件 长时间运行的操作。它不提供界面。一次 一项服务可能会继续运行一段时间,即使用户切换到另一项服务 应用。此外,组件可以绑定到服务以与其进行交互,甚至执行 进程间通信 (IPC)。例如,服务可以处理网络事务、 音乐、执行文件 I/O 或与内容提供程序互动,所有这一切都可以在后台进行。

关于Service类的许多困惑实际上都围绕着它不是什么:

  • Service不是一个独立的进程。Service对象本身并不意味着它在自己的进程中运行;除非另有指定,否则它在其所属的应用程序相同的进程中运行。
  • Service不是一个线程。它本身不是一种在主线程之外执行工作的手段(以避免应用程序无响应错误)。

Service实际上非常简单,提供了2个主要功能:

  • 一个功能是允许应用程序在后台运行处理事情 (甚至不需要有交互界面).当请求系统定时去处理事务时,可以调用 Context.startService()启动Service,一直运行Service,除非用户明确停止Service.
  • 一个功能是应用程序可以提供给其他应用一些功能,当为了与服务交互保持长期的连接时,可以调用Context.bindService(),绑定Service.

当Service组件被创建时,系统会实例化这个组件,并且会在主线程中回调onCreate()等方法。Service是否可以用适当的操作实现这些操作,例如创建一个可以工作的辅助线程。

因为Service如此简单,所以你可以通过想用的简单的或者复杂的方式与它交互。把Service当作Java本地对象,创造直接的回调方法(详细说明请看本地Service示例)通过AIDL提供全部远程接口。

二、生命周期 

系统启动Service有两种方式。通过调用Context.startService() 启动Service,然后系统检索到service后,创建它,并调用onCreate,然后通过客户端提供的参数回调onStartCommand(Intent, int, int)方法。 service会一直运行,直到调用Context.stopService() 或stopSelf() 停止Service. 请注意,对Context.startService()的多次调用不会嵌套 (多次调用start会回调多次onStartCommand()方法), 所以无论启动多少次service,只要调用一次Context.stopService() 或者stopSelf(),Service就会被停止。无论怎样,services可以用 stopSelf(int) 方法确保只有在intents开始处理后,才能停止service。

对于已经启动的services, 它们还可以选择以另外两种主要的运行模式运行,依赖于onStartCommand()的返回值: START_STICKY,表示services当被需要时,会被明确的启动或者停止。当使用START_NOT_STICKY or START_REDELIVER_INTENT 于服务时,服务当处理任何指令发送它们时,服务应该一直保持运行。详情请参考有关文档。

客户端也可以用Context.bindService()获取与service的持续连接。同样创建没有运行的服务,但是不回调onStartCommand()方法. 客户端可以收到从服务  onBind(Intent)方法返回的IBinder 对象,允许客户端制造回调给service。service运行时长和连接建立时长一样。通常 IBinder被返回给在aidl中创建的复杂接口。

service可以被启动或者绑定。 can be both started and have connections bound to it. 在这种情况下,系统可以保持service运行只要它被启动或者被绑定通过 Context.BIND_AUTO_CREATE 标识. 一旦这两种情况都不成立后,service的onDestroy() 方法会被调用或者有效的中断。所有的清理工作也应该在onDestroy()方法返回之前.

三、权限

当一个服务在其清单文件(manifest)的<service>标签中被声明时,可以强制实现对该服务的全局访问。通过上述操作,其他应用也需要声明对应的权限<uses-permission> 在自己的清单文件里,用以启动,停止,或绑定service.

Build.VERSION_CODES.GINGERBREAD(即Android 2.3姜饼版本)开始,当使用Context.startService(Intent)方法启动服务时,您还可以在Intent上设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或Intent.FLAG_GRANT_WRITE_URI_PERMISSION标志。这将授予服务对Intent中特定URI的临时访问权限。该访问权限将一直保留,直到服务为该启动命令或后续命令调用了stopSelf(int)方法,或者服务已经完全停止为止。

这适用于向那些没有请求保护服务的权限的其他应用授予访问权限,甚至当服务根本没有被导出时也同样有效。

另外,service可以用权限保护IPC调用,在执行调用实现之前需要调用ContextWrapper.checkCallingPermission(String) 方法。

查看Security and Permissions 文档,大体上详细讲述了权限和安全的内容。

四、进程生命周期

只要服务已被启动或有客户端绑定到该服务,Android系统就会尝试保持承载该服务的进程存活。当内存低时,需要杀死进程,保留service的进程根据下面可能性有更高的优先级:

  • 当前service执行代码在onCreate()onStartCommand(), 或onDestroy() 方法里, 所在进程将会成为前台进程,以确保代码执行期间进程不被杀死。

  • 服务已经被启动,所在进程被认为比其他可见进程优先级低,比其他任何不可见进程优先级高。因为一般只有一些对用户可见的进程除非在低内存下才会被杀死。然而,由于用户无法直接感知到后台服务的存在,在这种状态下,该服务被视为可被终止的有效候选对象,因此您应该为此做好准备。特别的是,对于长时间在后台运行的services会增加被killl掉的风险,且如果启动足够长的时间,确保被kill掉。

  • 如果客户端绑定service, 宿主进程比任何进程优先级都要高。如果客户端对用户是可见的,那么service本身对用户也是可见的。客户端影响了service重要性的通过设置如下标识实现的: Context.BIND_ABOVE_CLIENTContext.BIND_ALLOW_OOM_MANAGEMENTContext.BIND_WAIVE_PRIORITYContext.BIND_IMPORTANT, and Context.BIND_ADJUST_WITH_ACTIVITY.

  • 当被开启的service调用startForeground(int, android.app.Notification) 将service切换到前台,系统会认为用户知道service运行着处理事务,所以即使在低内存时,用户也不会kill掉service。 (理论上,在当前前台应用程序面临极端内存压力的情况下,该服务仍有可能被终止,但在实际操作中,这通常不必担心。)

大多数时候,运行着的service,在内存高度紧缺的情况下,依旧可能被kill掉。如果被kill掉,系统会在稍后重启service。这带来的一个重要后果是,如果您在onStartCommand()方法中安排异步执行工作或在其他线程中执行工作,那么您可能希望使用START_FLAG_REDELIVERY标志,以便系统在您的服务在处理Intent时被终止的情况下重新传递该Intent,从而确保它不会丢失。

当然,与服务运行在同一进程中的其他应用程序组件(如Activity)可以提高整个进程的重要性,而不仅仅是服务本身的重要性。

五、组件与绑定Service的通信方式

  对用于service中,一般使用bindService()启动服务。这是一种比startService更复杂的启动方式,同时使用这种方式启动的service也能完成更多的事情,比如其他组件可向其发送请求,接受来自它的响应,甚至通过它来进行IPC等等。我们通常将绑定它的组件称为客户端,而称它为服务端。 如果要创建一个支持绑定的service,我们必须要重写它的onBind()方法。这个方法会返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。而要得到IBinder接口,我们通常有三种方式:继承Binder类,使用Messenger类,使用AIDL。

跨进程通信方式有如下三种:

  • 扩展Binder类
  • Messenger信使
  • AIDL

后面两种可以跨进程通信,是基于Binder机制的通信方式。第一种我们多用于service直接的通信,但是当sevice被设为远程服务时(设为:remote),我们就要用后面两种方式来进行通信了。

Android系统中,如果组件与服务通信是在同一进程,就使用第一种方式;如果是跨进程通信,使用第二种和第三种,两者不同在于,Messenger不能处理多线程并发请求。​

1.扩展 Binder 类

如果我们的服务仅供本应用使用,无需跨进程,则可以实现自有 Binder 类,让客户端通过 Binder 类直接访问 Binder 或 Service 中提供的公共方法

如果您的服务仅对您自己的应用专用,并且在同一进程中运行 作为客户端(这很常见),请通过扩展 Binder 来创建接口 类别 并从中返回一个 onBind()。客户端收到 Binder 后,可利用它直接访问 Binder 实现或 Service 中提供的公共方法。

如果服务只是您自有应用的后台工作器,应优先采用这种方式。只有在这并非创建接口的首选方式时, 如果其他应用或不同的进程使用您的服务,则会发生该错误。

如果只有本地应用使用您的服务,且无需 跨进程工作 那么您可以实现自己的 Binder 类,为您的客户端直接提供 访问服务中的公共方法。

注意:只有当客户端和服务处于同一应用和进程内(最常见的情况)时,此方式才有效。例如,这非常适合于 这个应用需要将一个 activity 绑定到自己在 背景。

以下为设置方式:

  1. 在您的服务中,创建可执行以下某种操作的 Binder 实例:
    • 包含客户端可调用的公共方法。
    • 返回当前的 Service 实例,该实例中包含客户端可调用的公共方法。
    • 返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法。
  2. 从 onBind() 回调方法返回此 Binder 实例。
  3. 在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。

注意:服务和客户端必须在同一应用内,这样客户端才能转换返回的对象并正确调用其 API。服务 和客户必须在同一进程中,因为此方法不会执行任何 是跨进程编组的

举例

例如,以下服务可让客户端通过 Binder 实现访问服务中的方法:

服务端代码(MyService.kt)和客户端代码(ServiceDemoActivity.kt)demo项目源码下载请见

注意不要使用远程服务,如果一定要使用远程服务就要用后面的两种跨进程方式。

2.Messenger信使

如需让接口跨不同进程工作,您可以使用 Messenger 为服务创建接口。这样,服务 定义了一个 Handler,用于响应不同类型的 Message 对象。

这部Handler 是 Messenger 的基础,后者随后可以共享 IBinder 与客户端连接起来,让客户端使用 Message 对象向服务发送命令。此外,客户端还可以定义一个 Messenger 它自己的,因此服务可以发回消息。

这是执行进程间通信 (IPC) 最为简单的方式,因为 Messenger 会在单个线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。

如果您需要让服务与远程进程通信,则可使用 Messenger 为您的服务提供接口。利用这种方法, 无需使用 AIDL 即可执行进程间通信 (IPC)。

为接口使用 Messenger 比使用 AIDL 更简单,Messenger 会将所有服务调用加入队列,而纯 AIDL 接口会同时向服务发送多个请求,所以服务必须对多线程进行处理。对于大多数应用,服务无需执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。

如果我们的服务必须使用多线程,那么应该使用 AIDL 来定义接口。

以下是对 Messenger 使用方式的摘要:

  1. 服务实现一个 Handler,由其接收来自客户端的每个调用的回调。
  2. 服务使用 Handler 来创建 Messenger 对象(该对象是对 Handler 的引用)。
  3. Messenger 创建一个 IBinder,服务通过 onBind() 将其返回给客户端。
  4. 客户端使用 IBinder 将 Messenger(它引用服务的 Handler)实例化,然后再用其将 Message 对象发送给服务。
  5. 服务在其 Handler 中(具体而言,是在 handleMessage() 方法中)接收每个 Message

这样,客户端便没有调用服务的方法。相反,客户端会传递服务在其 Handler 中接收的消息(Message 对象)。

举例

下面这个简单的服务实例展示了如何使用 Messenger 接口。

 如果您想让服务做出响应,还需在客户端中创建一个 Messenger。当客户端收到 onServiceConnected() 回调时,会向服务发送一个 Message,并在其 send() 方法的 replyTo 参数中加入客户端的 Messenger。如需查看如何提供双向消息传递的示例,请看如下示例:

服务端代码(MessengerService.kt)和客户端代码(MessengerActivity.kt)demo项目源码下载请见

3.AIDL

Android官方推出了AIDL(Android Interface Definition Language),它是基于Binder机制的。

Android 接口定义语言 (AIDL) 可将对象分解为 操作系统可以识别这些基元并将其编组到各进程中以执行 IPC。之前采用 Messenger 的方法实际上是以 AIDL 为基础, 及其底层结构。

如上一部分所述,Messenger 会创建一个 所有客户端请求都在一个线程中完成,因此服务一次接收一个请求。不过,如果您想让服务同时处理多个请求,可以直接使用 AIDL。在这种情况下,您的服务必须具备线程安全性,并且能够进行多线程处理。

如需直接使用 AIDL,请执行以下操作: 创建一个定义编程接口的 .aidl 文件。Android SDK 工具会利用该文件生成实现接口和处理 IPC 的抽象类,您随后可在服务内对该类进行扩展。

注意:对于大多数应用来说,AIDL 并不是 创建绑定服务,因为它可能需要多线程处理能力 可以使实现过程更加复杂。

注意:必须使用 Java 编程语言构建 .aidl 文件。

默认情况下,AIDL 支持下列数据类型:

所有基本数据类型(如 int、long、char、boolean 等)
String
CharSequence
List:List 中所有元素必须是以上列出的数据类型或者我们声明的由 AIDL 生成的其他接口或 Parcelable 类型。
Map:Map 中所有元素必须是以上列出的数据类型或者我们声明的由 AIDL 生成的其他接口或 Parcelable 类型。
注意:即使在与接口相同的包内定义了上方未列出的其他类型,也必须要通过 import 导入这些类型。

服务端代码(RemoteService.kt, IRemoteService)和客户端代码(ClientActivity.kt)demo项目源码下载请见

七、总结

场景使用区别

那么,他们的使用场景分别是什么呢?

如果我们无需跨进程实现绑定服务和同一进程组件之间的通信,则使用 Binder 类即可
如果我们需要跨进程实现绑定服务和其他进程组件之间的通信,且不需要进行多线程处理时,则使用 Messenger
如果我们需要跨进程实现绑定服务和其他进程组件之间的通信,且需要进行多线程处理,则使用 AIDL.

首先,在实现的难度上,肯定是Messenger要简单的多——至少不需要写AIDL文件了(虽然如果认真的究其本质,会发现它的底层实现还是AIDL)。另外,使用Messenger还有一个显著的好处是它会把所有的请求排入队列,因此你几乎可以不用担心多线程可能会带来的问题。

但是这样说来,难道AIDL进行IPC就一无是处了么?当然不是,如果是那样的话它早就被淘汰了。一方面是如果项目中有并发处理问题的需求,或者会有大量的并发请求,这个时候Messenger就不适用了——它的特性让它只能串行的解决请求。另外,我们在使用Messenger的时候只能通过Message来传递信息实现交互,但是在有些时候也许我们需要直接跨进程调用服务端的方法,这个时候又怎么办呢?只能使用AIDL。

参考文章

绑定服务概览  |  Background work  |  Android Developers

Android跨进程通信Binder、Messenger、AIDL汇总_安卓 amessage 和 binder-CSDN博客

【Android】IPC 之 AIDL、Messenger 、Binder 浅析_安卓 amessage 和 binder-CSDN博客

​​​​​ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/92.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java_将数据存入elasticsearch进行高效搜索

使用技术简介&#xff1a; (1) 使用Nginx实现反向代理&#xff0c;使前端可以调用多个微服务 (2) 使用nacos将多个服务管理关联起来 (3) 将数据存入elasticsearch进行高效搜索 (4) 使用消息队列rabbitmq进行消息的传递 (5) 使用 openfeign 进行多个服务之间的api调用 参…

最近在盘gitlab.0.先review了一下docker

# 正文 本猿所在产品的代码是保存到了一个本地gitlab实例上&#xff0c;实例是别的同事搭建的。最近又又又想了解一下&#xff0c;而且已经盘了一些了&#xff0c;所以写写记录一下。因为这个事儿没太多的进度压力&#xff0c;索性写到哪儿算哪儿&#xff0c;只要是新了解到的…

计算机网络(四)网络层

4.1、网络层概述 简介 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 这些异构型网络N1~N7如果只是需要各自内部通信&#xff0c;他们只要实现各自的物理层和数据链路层即可 但是如果要将这些异构型网络互连起来&#xff0c;形成一个更大的互…

AI人工智能(2):机器学习

1 简介 机器学习&#xff08;Machine Learning&#xff09;是人工智能&#xff08;AI&#xff09;的一个分支&#xff0c;它使计算机系统能够利用数据和算法自动学习和改进其性能。机器学习是让机器通过经验&#xff08;数据&#xff09;来做决策和预测。机器学习已经广泛应用于…

Photon最新版本PUN 2.29 PREE,在无网的局域网下,无法连接自己搭建的本地服务器

1.图1为官方解答 2.就是加上这一段段代码&#xff1a;PhotonNetwork.NetworkingClient.SerializationProtocol SerializationProtocol.GpBinaryV16; 完美解决 unity 商店最新PUN 2 插件 不能连接 &#xff08;环境为&#xff1a;本地局域网 无外网情况 &#xff09; …

android 官网刷机和线刷

nexus、pixel可使用google官网线上刷机的方法。网址&#xff1a;https://flash.android.com/ 本文使用google线上刷机&#xff0c;将Android14 刷为Android12 以下是失败的线刷经历。 准备工作 下载升级包。https://developers.google.com/android/images?hlzh-cn 注意&…

Qt官方下载地址

1. 最新版本 Qt官方最新版本下载地址&#xff1a;https://www.qt.io/download-qt-installer 当前最新版本Qt6.8.* 如下图&#xff1a; 2. 历史版本 如果你要下载历史版本安装工具或者源码编译方式安装&#xff0c;请转至此链接进行下载&#xff1a;https://download.qt.i…

带格式 pdf 翻译

支持 openAI 接口&#xff0c;国内 deepseek 接口兼容 openAI 接口&#xff0c; deepseek api 又非常便宜 https://pdf2zh.com/ https://github.com/Byaidu/PDFMathTranslate

WebRTC 在视频联网平台中的应用:开启实时通信新篇章

在当今这个以数字化为显著特征的时代浪潮之下&#xff0c;实时通信已然稳稳扎根于人们生活与工作的方方面面&#xff0c;成为了其中不可或缺的关键一环。回首日常生活&#xff0c;远程办公场景中的视频会议让分散各地的团队成员能够跨越地理距离的鸿沟&#xff0c;齐聚一堂共商…

《ROS2 机器人开发 从入门道实践》 鱼香ROS2——第6章内容

第6章 建模与仿真-创建自己的机器人 6.1 机器人建模与仿真概述 6.2使用URDF创建机器人 6.2.1 帮机器人创建一个身体 1. 新建文件chapt6/chapt6_ws/src/fishbot_description/urdf/ 2. 新建文件first_robot.urdf <?xml version"1.0"?> <robot name &…

Postman接口测试03|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 七、Postman 1、安装 2、postman的界面介绍 八、Postman执行接口测试 1、请求页签 3、响应页签 九、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作-全局变量 1️⃣手动设置 2️⃣代码设置 3️⃣界面获取 4️⃣代…

【巨实用】Git客户端基本操作

本文主要分享Git的一些基本常规操作&#xff0c;手把手教你如何配置~ ● 一个文件夹中初始化Git git init ● 为了方便以后提交代码需要对git进行配置&#xff08;第一次使用或者需求变更的时候&#xff09;&#xff0c;告诉git未来是谁在提交代码 git config --global user.na…

下载导出Tomcat上的excle文档,浏览器上显示下载

目录 1.前端2.Tomcat服务器内配置3.在Tomcat映射的文件内放置文件4.重启Tomcat&#xff0c;下载测试 1.前端 function downloadFile() {let pictureSourceServer "http://192.168.1.1:8080/downFile/";let fileName "测试文档.xlsx";let fileURL pictu…

spring boot发送邮箱,java实现邮箱发送(邮件带附件)3中方式【保姆级教程一,代码直接用】

文章目录 Java发送邮箱的方式1. 基于 Javax.mail 实现关于附件上传的方法 2. 基于 org.apache.commons.mail 实现常见报错 3. 基于 spring-boot-starter-mail 实现&#xff08;推荐&#xff09; 实际开发时需要实现邮件发送&#xff0c;本文章实现如何从零实现邮件发送。也就是…

计算机网络期末复习(知识点)

概念题 在实际复习之前&#xff0c;可以看一下这个视频将网络知识串一下&#xff0c;以便更好地复习&#xff1a;【你管这破玩意叫网络&#xff1f;】 网络规模的分类 PAN&#xff08;个人区域网络&#xff09;&#xff1a;用于个人设备间的连接&#xff0c;如手机与蓝牙耳机…

Autoencoder(李宏毅)机器学习 2023 Spring HW8 (Boss Baseline)

1. Autoencoder 简介 Autoencoder是一种用于学习数据高效压缩表示的人工神经网络。它由两个主要部分组成: Encoder 编码器将输入数据映射到一个更小的、低维空间中的压缩表示,这个空间通常称为latent space或bottleneck。 这一过程可以看作是数据压缩,去除冗余信息,仅保留…

LLaMA-Factory web微调大模型并导出大模型

LLaMA-Factory 开源大模型如LLaMA&#xff0c;Qwen&#xff0c;Baichuan等主要都是使用通用数据进行训练而来&#xff0c;其对于不同下游的使用场景和垂直领域的效果有待进一步提升&#xff0c;衍生出了微调训练相关的需求&#xff0c;包含预训练&#xff08;pt&#xff09;&am…

一个基于Spring Boot的智慧养老平台

以下是一个基于Spring Boot的智慧养老平台的案例代码。这个平台包括老人信息管理、健康监测、紧急呼叫、服务预约等功能。代码结构清晰&#xff0c;适合初学者学习和参考。 1. 项目结构 src/main/java/com/example/smartelderlycare├── controller│ ├── ElderlyCon…

cmake - build MS STL project

文章目录 cmake - build MS STL project概述笔记END cmake - build MS STL project 概述 MS在github上开源了VS IDE 用的STL实现。 想看看微软的测试用例中怎么用STL. 想先用CMake编译一个MS STL发布版出来。 笔记 CMake需要3.30以上, 拟采用 cmake-3.30.6-windows-x86_64.…

【算法与数据结构】—— 回文问题

回文问题 目录 1、简介2、经典的回文问题(1) 判断一个字符串是否为回文(2) 给定字符集求构建的最长回文长度(3) 求最长回文子串方法一&#xff1a;中心拓展方法二&#xff1a;Manacher 算法 (4) 求回文子串的数目方法一&#xff1a;中心拓展方法二&#xff1a;Manacher 算法 1、…