Service服务在Android中的使用
目录
一,Service简介
二,Service的两种启动方式
1,非绑定式启动Service
2,绑定式启动Service
三,Service的生命周期
1,非绑定式Service的生命周期
2,绑定式Service的生命周期
四,前台Service
1,前台Service的创建
2,前台Service的结束
一,Service简介
Service服务,是指执行指定系统功能的程序,例程或进程,以便支持其他程序,并且运行期间用户不可见的一种活动机制,例如:后台播放音乐,后台下载等;
Service和Activity同属于一个级别,不同于子线程,service是运行在主线程中的,因此不能进行耗时操作;

二,Service的两种启动方式
(1)非绑定式启动(startService):
- 服务开启后与启动者没有任何关系,service的生命周期独立于启动者,启动者退出,service仍会运行;
- 启动者无法调用service中的方法;
(2)绑定式启动(bindService)
- 启动者(Activity)会和service绑定在一起,两者的生命周期会同步,当启动者退出时,service会跟着被销毁;
- 启动者可以调用service中的方法;
1,非绑定式启动Service
(1) 创建一个类继承Service类,并重写一系列方法:
public class MyService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i("MyService", "onBind: ");return null;}@Overridepublic void onCreate() {Log.i("MyService", "onCreate: ");super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("MyService", "onStartCommand: ");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i("MyService", "onDestroy: ");super.onDestroy();}
}
(2)在Manifest文件中注册指定Service:

(3)调用startService(Intent intent)方法启动Service:
private void startMyService() {Intent intent = new Intent(this, MyService.class);startService(intent);
}
2,绑定式启动Service
(1)前两步与非绑定式启动一致,创建Service子类并注册Service:
public class MyBindService extends Service {private final String TAG = "MyBindService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return new MyBinder(this);}@Overridepublic void onCreate() {Log.i(TAG, "onCreate: ");super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand: ");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i(TAG, "onDestroy: ");super.onDestroy();}@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG, "onUnbind: ");return super.onUnbind(intent);}
}
(2)绑定式启动Service需要调用bindService()方法,这个方法需要三个参数:
private void startBindService() {Intent intent = new Intent(this, MyBindService.class);isBound = bindService(intent, connection, BIND_AUTO_CREATE);
}
Intent:表示启动意图,也就是想要启动的Service;
connection:相当于启动者(Activity)和Service之间的连接,通过一系列的回调函数来监听访问者和Service的连接情况;
int flag:绑定时是否自动创建Service,这里选择自动创建BIND_AUTO_CREATE;
除了Intent和flag外,我们还需创建一个connection,这里通过匿名内部类的形式创建,并重写两个回调方法。这里onServiceConnected方法中有一个IBinder类型的service,这个service起到了中间人的作用,通过这个service,启动者(Activity)就可以调用Service中的方法:
private ServiceConnection connection = new ServiceConnection() {//创建连接时回调@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//这里 IBinder类型的service 就是我们要绑定的那个service//通过这个service,Activity就可以调用MyBindService.MyBinder中的方法}//断开连接时回调@Overridepublic void onServiceDisconnected(ComponentName name) {Log.i(TAG, "onServiceDisconnected: ");}
};
那么这个service是从哪来的呢?
在我们创建的Service子类中,我们重写了一个onBind的方法,返回的正好是一个IBinder类型的值,这个返回值也就是会传给上面service的值。
@Override
public IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return new MyBinder(this);
}
所以我们可以在Service子类中创建一个类继承自Binder(Binder实现了IBinder接口),这样Activity通过connection中的service就可以调用MyBinder类中的方法;
进一步,通过构造方法,我们可以将Service传给MyBinder,这样在MyBinder中就可以调用我们Service中的方法,又因为Activity可以调用MyBinder中的方法,所以我们就实现了Activity调用Service的方法,这也就是为什么绑定式启动Service,启动者(Activity)可以调用Service中的方法;
@Override
public IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return new MyBinder(this);
}public void Test(){//Log.i(TAG, "Test: MyBindService的Test方法被调用");
}public class MyBinder extends Binder{private MyBindService myBindService;public MyBinder(){}public MyBinder(MyBindService bindService){this.myBindService = bindService;}public void Test(){//Log.i(TAG, "Test: MyBinder的Test方法被调用");//这样MyBinder就可以调用MyBindService中的方法//MyBinder作为一个中间人 Activity调用MyBinder的方法 -> MyBinder再调用Service的方法myBindService.Test();}
}
绑定式启动Service的全部流程代码:
Activity:
public class MainActivity extends AppCompatActivity {private final String TAG = "MainActivity";private Boolean isBound = false;private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());setLinsteners();}private void setLinsteners() {binding.btnStartBindService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startBindService();}});}private void startBindService() {Intent intent = new Intent(this, MyBindService.class);isBound = bindService(intent, connection, BIND_AUTO_CREATE);}private MyBindService.MyBinder myBindService;private ServiceConnection connection = new ServiceConnection() {//创建连接时回调@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//这里 IBinder类型的service 就是我们要绑定的那个service//通过这个service,Activity就可以调用MyBindService.MyBinder中的方法myBindService = (MyBindService.MyBinder)service;myBindService.Test();}//断开连接时回调@Overridepublic void onServiceDisconnected(ComponentName name) {Log.i(TAG, "onServiceDisconnected: ");//Intent intent = new Intent(MainActivity.this, MyBindService.class);//stopService(intent);}};
}
Service:
public class MyBindService extends Service {private final String TAG = "MyBindService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return new MyBinder(this);}public void Test(){//Log.i(TAG, "Test: MyBindService的Test方法被调用");}public class MyBinder extends Binder{private MyBindService myBindService;public MyBinder(){}public MyBinder(MyBindService bindService){this.myBindService = bindService;}public void Test(){//Log.i(TAG, "Test: MyBinder的Test方法被调用");//这样MyBinder就可以调用MyBindService中的方法//MyBinder作为一个中间人 Activity调用MyBinder的方法 -> MyBinder再调用Service的方法myBindService.Test();}}@Overridepublic void onCreate() {Log.i(TAG, "onCreate: ");super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand: ");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i(TAG, "onDestroy: ");super.onDestroy();}@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG, "onUnbind: ");return super.onUnbind(intent);}}
三,Service的生命周期
1,非绑定式Service的生命周期
启动阶段:启动者(Activity)调用startService
- onCreate():Service被创建时调用,整个生命周期中只会被调用一次;
onStartCommand():每次调用startService时,该方法会被调用,该方法接收Intent参数,从而可以执行一些命令;
结束阶段:启动者调用stopService()方法或Service内部调用stopSelf()方法;
- onDestroy():Service销毁时调用,与onCreate一样,整个生命周期中只会被调用一次;
2,绑定式Service的生命周期
启动阶段:启动者(Activity)调用bindService
- onCreate():Service被创建时调用,整个生命周期中只会被调用一次;
- onBind():在首次绑定时会被调用一次,同样整个生命周期中只会被调用一次;
结束阶段:当启动者销毁或unBindService方法时,启动者会和Service解除绑定,当没有任何绑定者时,Service会被销毁;
- onUnbind():解除绑定时调用,可多次调用;
- onDestroy():Service销毁时调用,整个生命周期中只会被调用一次;

四,前台Service
前台Service,即可以与用户进行交互的运行在前台的Service,优先级相比于其他两种运行在后台的Service要高,最常见的应用就是通知栏前台控制音乐播放;

1,前台Service的创建
在正常的Service中调用startForeground() 方法即可将正常服务提升为前台服务,startForeground()方法需要接收一个通知对象,因为前台Service必须在通知栏中进行通知;
public class MyForeGroundService extends Service {private final String TAG = "MyForeGroundService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return null;}@Overridepublic void onCreate() {super.onCreate();Log.i(TAG, "onCreate: ");//创建一个通知NotificationManager notificationManager = (NotificationManager) getApplication().getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel channel = new NotificationChannel("channel_id","channel_name",notificationManager.IMPORTANCE_HIGH);notificationManager.createNotificationChannel(channel);Notification.Builder builder = new Notification.Builder(this,"channel_id");Notification notification = builder.build();//将服务提升为前台服务startForeground(1, notification);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand: ");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i(TAG, "onDestroy: ");super.onDestroy();}}
2,前台Service的结束
前台Service的结束有两种含义:
(1)结束Service本身:通过启动者调用stopService方法或Service内部调用stopSelf方法正常结束Service,Service结束后,通知也会随之移除;
(2)前台Service降级为后台Service:通过Service内部调用stopForeground(true)方法将Service退出后台状态,此时Service不会被销毁,当内存不足时,Service可能会被回收。参数true表示移除通知;
前台Service创建和结束的全部流程代码:
Activity:
public class MainActivity extends AppCompatActivity {private final String TAG = "MainActivity";private Boolean isBound = false;private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());setLinsteners();}private void setLinsteners() {//创建前台Servicebinding.btnStartForeGroundService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, MyForeGroundService.class);startService(intent);}});//移除前台Servicebinding.btnStopForeGroundService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, MyForeGroundService.class);intent.putExtra("key_stop", "stopForeGround");startService(intent);}});}}
Service:
public class MyForeGroundService extends Service {private final String TAG = "MyForeGroundService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return null;}@Overridepublic void onCreate() {super.onCreate();Log.i(TAG, "onCreate: ");//创建一个通知NotificationManager notificationManager = (NotificationManager) getApplication().getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel channel = new NotificationChannel("channel_id","channel_name",notificationManager.IMPORTANCE_HIGH);notificationManager.createNotificationChannel(channel);Notification.Builder builder = new Notification.Builder(this,"channel_id");Notification notification = builder.build();//将服务提升为前台服务startForeground(1, notification);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand: ");String keyStop = intent.getStringExtra("key_stop");if(TextUtils.equals(keyStop, "stopForeGround")){stopForeground(true);//true表示移除通知}return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i(TAG, "onDestroy: ");super.onDestroy();}}相关文章:
Service服务在Android中的使用
目录 一,Service简介 二,Service的两种启动方式 1,非绑定式启动Service 2,绑定式启动Service 三,Service的生命周期 1,非绑定式Service的生命周期 2,绑定式Service的生命周期 四…...
浅谈C语言位段
1、位段的定义 百度百科中是这样解释位段的: 位段,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。 以下,我们均在VS2022的…...
arcgisserver登陆信息不正确
密码明明对,但是登录提示登录信息不正确 Arcgis server 9.3.1 无法登录ArcGIS Manager 提示Incorrect Login Information 操作系统windows 2008 x64server 解决办法: 关闭window防火墙解决。 如果防火墙已经关闭: 通过修改用户口令后就可以重…...
KOLA: CAREFULLY BENCHMARKING WORLD KNOWLEDGE OF LARGE LANGUAGE MODELS
文章目录 题目摘要简介KOLA 基准实验评估结论和未来工作道德声明 题目 KOLA:仔细对大型语言模型的世界知识进行基准测试 论文地址:https://arxiv.org/abs/2306.09296 项目地址:https://github.com/ranahaani/GNews 摘要 大型语言模型 (LLM) 的卓越性能要求评估方法…...
Robot Operating System——机器人关节的角度、速度和力矩
大纲 应用场景定义字段解释 案例 sensor_msgs::msg::JointState 是 ROS (Robot Operating System) 中的一个消息类型,用于表示机器人关节的状态信息。它通常用于传输和处理机器人关节的角度、速度和力矩等信息。 应用场景 机器人控制 关节控制:在机器人…...
一分钟掌握java9新特性
try-with-resources语句 /** * 在处理必须关闭的资源时,使用try-with-resources语句替代try-finally语句。 生成的代码更简洁,更清晰,并且生成的异常更有用 * java9 之前写法 */ public static String readFile1(String fileName){ tr…...
89. UE5 RPG 实现伤害 冷却 消耗技能描述
在上一篇文章里,我们能够通过富文本显示多种格式的文字,并显示技能描述。在这一篇文章里,我们继续优化技能描述,将技能说需要显示的内容显示出来。 实现火球术的基础描述 首先,我们现实现火球术的基础描述࿰…...
el-tree树状控件,定位到选中的节点的位置
效果图 在el-tree 控件加 :render-content"renderContent" 在掉接口的方法中 实际有用的是setTimeout 方法和this.$refs.xxxxxx.setCheckedKeys([industrycodeList]) if(res.data.swindustrylist.length>0){res.data.swindustrylist.forEach(item > {industry…...
YOLO目标检测的单目(多目标测距),使用相机光学模型,支持目标检测模型训练,可输出目标位置和距离信息并可视化
本项目旨在开发一个基于YOLO的目标检测系统,该系统不仅能检测图像中的多个目标,还能利用单目摄像头的图像估计每个目标与摄像头之间的相对距离。系统的核心组成部分包括目标检测、距离估计、模型训练以及结果可视化。 主要功能 目标检测:使用…...
unity简易lua文件迁移工具
一. 了解商业游戏的Lua热更新开发方式 市面上的3种结合Lua热更新的开发方式 1.纯Lua开发(所有的游戏主要逻辑都用Lua实现) 好处:机动性强;坏处:代码效率略差 2.半C#,半Lua开发(核心逻辑C#开发…...
Elasticsearch中的自动补全功能详解与实践
简介 自动补全是现代搜索引擎中的一项重要功能,它能够根据用户的输入提供实时的建议,提高用户体验。Elasticsearch提供了Completion Suggester查询来实现这一功能。本文将详细介绍Elasticsearch中的自动补全功能,并提供详细的配置和查询示例…...
前端如何使用Nginx代理dist网页,代理websocket,代理后端
本文将指导您如何配置Nginx以代理前后端分离的项目,并特别说明了对WebSocket的代理设置。通过本教程,您将能够实现一次性配置,进而使项目能够在任意局域网服务器上部署,并可通过IP地址或域名访问服务。 笔者建议 先速览本文了解大…...
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. 问题解决
问题描述 原来我的服务器docker服务运行正常,但在某次尝试用时, 根据系统的错误提示执行了snap install docker指令之后, 再执行docker ps命令则提示Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running…...
零基础学习Redis(2) -- Redis安装与配置
Redis官方是并不支持Windows系统的,并且现在绝大部分公司都是使用的Linux,所以我们在Linux上进行安装,这里我使用的是Ubuntu 1. 安装步骤 1. 首先使用工具连接到我们的云服务器,然后输入apt指令搜索redis相关的软件包࿱…...
UniApp第一天
一、官网介绍 1.1、 SDK SDK是"Software Development Kit"的缩写,中文意思是“软件开发工具包”。SDK通常是由软件开发者为其他开发者提供的一个软件工具集合,用于帮助开发者快速开发、测试和部署软件应用。SDK通常包含了一系列的开发工具、库…...
TLE4966-3G带方向检测功能的高灵敏度汽车霍尔开关
TLE4966-3G是一款集成电路双霍尔效应传感器,专为使用旋转极轮的高精度应用而设计。通过片上有源补偿电路和斩波器技术实现精确的磁切换点和高温稳定性。 该传感器在Q2提供速度输出,其状态(高或低)与磁场值相对应。对于超过阈值BO…...
Github 2024-08-14 C开源项目日报Top10
根据Github Trendings的统计,今日(2024-08-14统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10Objective-C项目1PHP项目1Python项目1PHP:流行的Web开发脚本语言 创建周期:4710 天开发语言:C, PHP协议类型:OtherStar数量:37340 …...
飞桨Paddle API index_add 详解
index_add paddle.index_add(x, index, axis, value, nameNone)[源代码] 沿着指定轴 axis 将 index 中指定位置的 x 与 value 相加,并写入到结果 Tensor 中的对应位置。这里 index 是一个 1-D Tensor。除 axis 轴外,返回的 Tensor 其余维度大小和输入 …...
后端代码练习1——加法计算器
1. 需求 输入两个整数,点击 “点击相加” 按钮,显示计算结果。 2.准备工作 创建Spring Boot项目,引入Spring Web依赖,把前端代码放入static目录下。 2.1 前端代码 <!DOCTYPE html> <html lang"en"> <h…...
观察者模式和MQ是什么关系
观察者模式(Observer Pattern)和MQ(Message Queue,消息队列)之间的关系主要体现在它们所实现的功能和机制上的相似性,尽管它们在技术实现和应用场景上有所不同。 观察者模式 观察者模式是一种行为型设计模…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
raid存储技术
1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划,涵盖存储系统的布局、数据存储策略等,它明确数据如何存储、管理与访问,为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...
CSS 工具对比:UnoCSS vs Tailwind CSS,谁是你的菜?
在现代前端开发中,Utility-First (功能优先) CSS 框架已经成为主流。其中,Tailwind CSS 无疑是市场的领导者和标杆。然而,一个名为 UnoCSS 的新星正以其惊人的性能和极致的灵活性迅速崛起。 这篇文章将深入探讨这两款工具的核心理念、技术差…...
