当前位置: 首页 > news >正文

Android绑定式服务

Github:https://github.com/MADMAX110/Odometer
启动式服务对于后台操作很合适,不过需要一个更有交互性的服务。
接下来构建这样一个应用:
1、创建一个绑定式服务的基本版本,名为OdometerService
我们要为它增加一个方法getDistance(),这个方法会返回一个随机数
2、让活动MainActivity绑定到OdometerService,并调用它的getDistance方法。
将每秒调用一次这个方法,在MainActivity中用得到的结果更新一个文本视图。
3、更新OdometerService,改为使用Android的位置服务。
这个服务将得到用户当前位置的更新,并使用这些更新计算所走过的距离。

创建一个名为Odometer的Android新工程

在这里插入图片描述

创建一个新服务

要创建一个绑定式服务,需要扩展Service类。
如图所示,在com.hfad.odometer中创建一个服务。
不要选中Exported,因为只有当希望这个应用之外的服务能够访问这个服务时才需要将它设置为true。
确保选中Enabled,不选中的话活动将无法运行应用。
在这里插入图片描述

package com.hafd.odometer;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;public class OdometerService extends Service {@Overridepublic IBinder onBind(Intent intent) {}
}

上面的代码实现了一个方法onBind,当一个组件希望绑定到这个服务时,会调用这个方法。这个方法有一个参数Intent,并返回一个IBinder对象。
IBinder是一个接口,用来将你的服务绑定到活动,需要在服务代码中提供它的一个实现。

实现一个绑定器

定义绑定器:

    public class OdometerBinder extends Binder {OdometerService getOdometer() {return OdometerService.this;}}

更新OdometerService.java代码并增加一个getDistance方法

package com.hafd.odometer;import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import java.util.Random;public class OdometerService extends Service {private final IBinder binder = new OdometerBinder();private final Random random = new Random();//创建一个绑定式服务时,需要提供一个Binder实现public class OdometerBinder extends Binder {//活动将使用这个方法得到OdometerService的一个引用OdometerService getOdometer() {return OdometerService.this;}}@Overridepublic IBinder onBind(Intent intent) {return binder;}public double getDistance() {return random.nextDouble();}
}

更新MainActivity的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"android:padding="16dp"><TextViewandroid:id="@+id/distance"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="48sp"android:layout_gravity="center_horizontal"android:textAppearance="?android:attr/textAppearanceLarge" /></LinearLayout>

MainActivity需要做什么

1、创建一个ServiceConnection

ServiceConnection是一个接口,允许将活动绑定到一个服务。
它有两个方法需要你定义:
onServiceConnected():建立与服务的连接时会调用
onServiceDisconnected():断开服务连接时会调用
更新MainActivity.java

    package com.hafd.odometer;import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;public class MainActivity extends AppCompatActivity {private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {}@Overridepublic void onServiceDisconnected(ComponentName componentName) {}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}
onServiceConnected方法

在活动和服务之间建立连接时会调用这个方法。
有两个参数:一个ComponentName对象和一个IBinder对象,ComponentName对象描述所要连接的服务,IBinder对象由服务定义。
我们使用onServiceConnected方法做两件事:
1、使用它的IBinder参数得到所连接服务的一个引用,在这里就是OdometerService的引用。为此可以将IBinder强制转换为一个OdometerService.OdometerBinder,并调用它的getOdometer方法。
2、记录活动绑定到这个服务。

    private OdometerService odometer;private boolean bound = false;private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {OdometerService.OdometerBinder odometerBinder = (OdometerService.OdometerBinder) iBinder;odometer = odometerBinder.getOdometer(); //使用IBinder得到服务的一个引用bound = true;}@Overridepublic void onServiceDisconnected(ComponentName componentName) {bound = false;}};
onServiceDisconnected方法

记录活动不再绑定到服务。

public void onServiceDisconnected(ComponentName componentName) {bound = false;}

2、将活动绑定到服务

使用bindService绑定服务

通常会在两个地方将活动绑定到服务:
活动变得可见时,在活动的onStart方法中,如果只需要在活动可见时与活动交互,在这个方法中绑定服务就很合适。
活动创建时,在活动的onCreate方法中,如果需要从服务接受更新,即使活动已经停止也要继续接受更新,就要在这个方法中绑定服务。
在这里我们只需要在MainActivity可见时显示从OdometerService得到的更新,所以要在活动的onStart方法中绑定服务。
要绑定这个服务首先要创建一个显式意图,指定想要绑定的服务。然后使用活动的bindService方法绑定服务,传入这个意图,服务定义的ServiceConnection对象以及描述希望如何绑定的一个标志。

    @Overrideprotected void onStart() {super.onStart();Intent intent = new Intent(this, OdometerService.class);bindService(intent, connection, Context.BIND_AUTO_CREATE);}

3、与服务交互

调用OdometerService的getDistance方法
一旦活动绑定到服务,我们要每秒调用一次OdometerService的getDistance方法,并将其值更新MainActivity的文本视图。
为MainActivity增加一个displayDistance方法:

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);displayDistance();}private void displayDistance() {final TextView distanceView = (TextView) findViewById(R.id.distance);final Handler handler = new Handler();handler.post(new Runnable() {@Overridepublic void run() {double distance = 0.0;//如果得到OdometerService的一个引用,而且绑定到这个服务,则调用getDistance。if (bound && odometer != null)distance = odometer.getDistance();String distanceStr = String.format(Locale.getDefault(), "%1$,.2f miles", distance);distanceView.setText(distanceStr);//每秒运行一次handler.postDelayed(this, 1000);}});}

4、完成时与服务接触绑定

使用unbindService与服务解除绑定

将活动与服务解除绑定时,通常会把相应的代码增加到活动的onStop或onDestroy方法中。使用哪一个方法取决于你的bindService代码放在哪里:
如果在活动的onStart方法中绑定服务,则在onStop方法中解除绑定。
如果在onCreate方法中绑定服务,则在onDestroy方法中解除绑定。
所以这里在onStop方法与服务解除绑定。这个方法有一个参数,即ServiceConnection对象。需要向MainActivity增加以下代码:

    protected void onStop() {super.onStop();if (bound) {unbindService(connection);bound = false;}}

试一试应用

运行这个应用时会在MainActivity显示一个随机数,这个数每秒改变一次。
在这里插入图片描述

安卓绑定式服务的生命周期

1、服务创建
2、onCreate(): 当服务第一次被创建时执行。这个方法可以在服务创建时进行一些初始化操作。
3、onBind(): 当其他组件通过调用bindService()方法与服务绑定时执行。在这个方法中,服务会返回一个IBinder接口实例,客户端可以通过这个接口与服务进行通信。
4、服务绑定
5、onUnbind(): 当其他组件通过调用unbindService()方法与服务解绑时执行。在这个方法中,服务可以执行一些清理操作,例如停止在后台运行的任务等。
6、onDestroy(): 当服务不再被使用或被销毁时执行。注意,如果服务同时被启动和绑定,那么即使所有的客户端都解绑了服务,服务也不会被销毁,除非服务用stopSelf()方法或其他组件调用stopService()方法来终止自己。
7、服务撤销

总的来说,绑定式服务的生命周期与启动式服务的生命周期略有不同,主要区别在于绑定式服务需要与其他组件进行绑定和解绑操作,并且服务的生命周期会受到这些操作的影响。

相关文章:

Android绑定式服务

Github:https://github.com/MADMAX110/Odometer 启动式服务对于后台操作很合适&#xff0c;不过需要一个更有交互性的服务。 接下来构建这样一个应用&#xff1a; 1、创建一个绑定式服务的基本版本&#xff0c;名为OdometerService 我们要为它增加一个方法getDistance()&#x…...

系统韧性研究(1)| 何谓「系统韧性」?

过去十年&#xff0c;系统韧性作为一个关键问题被广泛讨论&#xff0c;在数据中心和云计算方面尤甚&#xff0c;同时它对赛博物理系统也至关重要&#xff0c;尽管该术语在该领域不太常用。大伙都希望自己的系统具有韧性&#xff0c;但这到底意味着什么&#xff1f;韧性与其他质…...

使用Perl脚本编写爬虫程序的一些技术问题解答

网络爬虫是一种强大的工具&#xff0c;用于从互联网上收集和提取数据。Perl 作为一种功能强大的脚本语言&#xff0c;提供了丰富的工具和库&#xff0c;使得编写的爬虫程序变得简单而灵活。在使用的过程中大家会遇到一些问题&#xff0c;本文将通过问答方式&#xff0c;解答一些…...

SAP内部转移价格(利润中心转移价格)的条件

SAP内部转移价格&#xff08;利润中心转移价格&#xff09; SAP内部转移价格&#xff08;利润中心转移价格&#xff09; SAP内部转移价格&#xff08;利润中心转移价格&#xff09;这个听了很多人说过&#xff0c;但是利润中心转移定价需要具备什么条件。没有找到具体的文档。…...

WRF如何批量输出文件添加或删除文件名后缀

1. 批量添加文件名后缀 #1----批量添加文件名后缀&#xff08;.nc&#xff09;。#指定wrfout文件所在的文件夹 path "/mnt/wtest1/"#列出路径path下所有的文件 file_names os.listdir(path) #遍历在path路径下所有以wrfout_d01开头的文件&#xff0c;在os.path…...

Ubuntu右上角不显示网络的图标解决办法

一.line5改为true sudo vim /etc/NetworkManager/NetworkManager.conf 二.重启网卡 sudo service network-manager stop sudo mv /var/lib/NetworkManager/NetworkManager.state /tmp sudo service network-manager start...

AM@数列极限

文章目录 abstract极限&#x1f47a;极限的主要问题 数列极限数列极限的定义 ( ϵ − N ) (\epsilon-N) (ϵ−N)语言描述极限表达式成立的证明极限发散证明常用数列极限数列极限的几何意义例 函数的极限 abstract 数列极限 极限&#x1f47a; 极限分为数列的极限和函数的极限…...

Vue-2.3v-model原理

原理&#xff1a;v-model本质上是一个语法糖&#xff0c;例如应用在输入框上&#xff0c;就是value属性和input事件的合写。 作用&#xff1a;提供数据的双向绑定 1&#xff09;数据变&#xff0c;视图跟着变:value 2&#xff09;视图变&#xff0c;数据跟着变input 注意&a…...

​左手 Serverless,右手 AI,7 年躬身的古籍修复之路

作者&#xff1a;宋杰 “AI 可以把我们思维体系当中&#xff0c;过度专业化、过度细分的这些所谓的知识都替代掉&#xff0c;让我们集中精力去体验自己的生命。我挺幸运的&#xff0c;代码能够有 AI 辅助&#xff0c;也能够有 Serverless 解决我的运营成本问题。Serverless 它…...

计算mask的体素数量

import numpy as np import nibabel as nib # 用于处理神经影像数据的库 # 从文件中加载mask图像 mask_image nib.load(rE:\mask.nii.gz) # 获取图像数据 mask_data mask_image.get_fdata() # 计算非零像素的数量&#xff0c;即白质骨架的体素总数 voxel_count np.count_no…...

VR全景营销颠覆传统营销,让消费者身临其境

随着VR的普及&#xff0c;各种VR产品、功能开始层出不穷&#xff0c;并且在多个领域都有落地应用&#xff0c;例如文旅、景区、酒店、餐饮、工厂、地产、汽车等&#xff0c;在这个“内容为王”的时代&#xff0c;VR全景展示也是一种新的内容表达方式。 VR全景营销让消费者沉浸式…...

FreeRTOS学习笔记——四、任务的定义与任务切换的实现

FreeRTOS学习笔记——四、任务的定义与任务切换的实现 0 前言1 什么是任务2 创建任务2.1 定义任务栈2.2 定义任务函数2.3 定义任务控制块2.4 实现任务创建函数2.4.1 任务创建函数 —— xTaskCreateStatic()函数2.4.2 创建新任务——prvInitialiseNewTask()函数2.4.3 初始化任务…...

js 之让人迷惑的闭包 03

文章目录 一、闭包是什么&#xff1f; &#x1f926;‍♂️二、闭包 &#x1f60e;三、使用场景 &#x1f601;四、使用场景&#xff08;2&#xff09; &#x1f601;五、闭包的原理六、思考总结一、 更深层次了解闭包&#xff0c;分析以下代码执行过程二、闭包三、闭包定义四、…...

10月10日上课内容 Docker--harbor私有仓库部署与管理

Docker--harbor私有仓库部署与管理 ------------------ 1、搭建本地私有仓库 ------------------------------ #首先下载 registry 镜像 docker pull registry #在 daemon.json 文件中添加私有镜像仓库地址 vim /etc/docker/daemon.json { "insecure-registries"…...

Java 序列化和反序列化为什么要实现 Serializable 接口

第一、序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化. 反序列化&#xff1a;把字节序列恢复为对象的过程称为对象的反序列化. 第二、什么时候需要用序列化和反序列化呢? 当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和…...

vite+vue3+ts中使用require.context | 报错require is not defined | 获取文件夹中的文件名

vitevue3ts中使用require.context|报错require is not defined|获取文件夹中的文件名 目录 vitevue3ts中使用require.context|报错require is not defined|获取文件夹中的文件名一、问题背景二、报错原因三、解决方法 一、问题背景 如题在vitevue3ts中使用required.context时报…...

C#(Csharp)我的基础教程(四)(我的菜鸟教程笔记)-Windows项目结构分析、UI设计和综合事件应用的探究与学习

目录 windows项目是我们.NET学习一开始必备的内容。 1、窗体类&#xff08;主代码文件窗体设计器后台代码文件&#xff09; 主窗体对象的创建&#xff1a;在Program类里面&#xff1a; Application.Run(new FrmMain());这句代码就决定了&#xff0c;当前窗体是项目的主窗体。…...

Flink: Only supported for operators

Exception in thread "main" java.lang.UnsupportedOperationException: Only supported for operators.at org.apache.flink.streaming.api.scala.DataStream.name(...

NSIDC定义的海冰相关概念

文章目录 相关概念Matlab绘图结果展示 相关概念 NSIDC 表示 “National Snow and Ice Data Center”&#xff0c;即美国国家雪和冰数据中心。NSIDC 是一个位于美国科罗拉多大学波尔得分校的研究中心&#xff0c;致力于收集、管理和分发全球雪和冰的科学数据。 Matlab绘图 cl…...

【码银送书第八期】《Python数据挖掘:入门进阶与实用案例分析》

摘要&#xff1a;本案例将主要结合自动售货机的实际情况&#xff0c;对销售的历史数据进行处理&#xff0c;利用pyecharts库、Matplotlib库进行可视化分析&#xff0c;并对未来4周商品的销售额进行预测&#xff0c;从而为企业制定相应的自动售货机市场需求分析及销售建议提供参…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...