如何在 Android 项目中实现跨库传值
背景介绍
在一个复杂的 Android 项目中,我们通常会有多个库(lib),而主应用程序(app)依赖所有这些库。目前遇到的问题是,在这些库中,libAd
需要获取 libVip
的 VIP 等级状态,但这两个库之间没有直接依赖关系。
问题分析
一种不太优雅的解决方案是直接让 libAd
依赖 libVip
,这样虽然能快速解决问题,但会带来多个潜在缺点:
-
依赖混乱:
当库之间形成直接依赖时,会导致项目的依赖关系变得复杂且难以管理。每增加一个新的依赖,都可能影响到项目的构建时间、性能以及可移植性。 -
违反单一职责原则(Single Responsibility Principle, SRP):
libAd
本应专注于广告相关功能,而不是负责管理 VIP 状态。如果它依赖于libVip
,则意味着它同时承担了额外的责任,使其更难维护。 -
降低模块化和可复用性:
增加不必要的依赖会使得库变得不够独立,降低了它们的可重用性。此后若要将这些库用于其他项目,还需要处理不相关的依赖关系。 -
演变成紧耦合系统:
随着项目的发展,如果每个模块都通过直接依赖来获取所需信息,整个系统将逐渐演变为紧耦合的体系结构。这种结构让系统中的一个变化可能导致一连串的调整,增加了维护成本和复杂性。 -
违反开闭原则(Open/Closed Principle, OCP):
系统应该对扩展开放,对修改关闭。直接依赖使得系统在面对需求变化时,需要频繁修改已有代码,而不是通过扩展实现新功能。
因此,我们需要寻找一种更好的方法来实现跨库的数据传递,以保持库之间的独立性和系统的灵活性,同时遵循良好的设计原则,从而提高代码的可维护性和可扩展性。
简单方案的缺陷
一个简单的方法是利用已有的 libNet
库作为中介。这种方法基于以下前提和依赖关系:
-
现有依赖关系:
在当前项目结构中,libAd
和libVip
都已经依赖于libNet
。这意味着它们都能够访问libNet
提供的功能,而无需额外增加任何新的直接库间依赖。 -
中介模式的应用:
- 通过使用
libNet
作为中介,我们可以在不直接修改libAd
和libVip
的情况下,实现它们之间的数据传递。具体做法如下:- 当
libVip
的 VIP 等级发生变化时,它会调用libNet
的setVipInfo(String info)
方法,将最新的信息存储在libNet
中。 - 当
libAd
需要查询 VIP 信息时,它会调用libNet
的getVipInfo()
方法,从而获得最新的 VIP 数据。
- 当
- 通过使用
-
优势与权衡:
- 优势:这种方法利用了已有的依赖关系,不需要引入新的依赖或大幅度改变系统架构。
- 缺点:虽然实现简单,但
libNet
的设计初衷可能并不是作为数据共享平台,这样的用途可能会使其承担过多职责,违反单一职责原则,同时数据更新的及时性也无法得到保证。
通过这种方式,我们能在短时间内解决跨库数据传递的问题,不过从长远来看,仍需考虑更符合设计原则的重构方案,以保持代码的清晰性和可维护性。
推荐方案:使用 app
作为中介
由于 app
本身依赖于 libAd
和 libVip
,所以我们可以在 app
层面处理这种数据传递。下面介绍具体实现步骤:
1. 为 libAd
添加接口
首先,为 libAd
新增一个接口,用于同步 libVip
的数据:
/*** libAd 同步 libVip 的数据* 如果需要同步其他无依赖关系的库的数据,可以继续新增方法*/
public interface LibAdDataListener {/*** @return 是否是 Vip*/boolean isVip();/*** @return 获取当前 VIP 类型*/String getVipType();
}
2. 在 libAd
的管理类中新增方法
在 AdManager
类中添加以下方法,用于设置和获取数据监听器:
private LibAdDataListener dataListener;public AdManager setSharedDataListener(LibAdDataListener dataListener) {this.dataListener = dataListener;return this;
}public LibAdDataListener getSharedDataListener() {return dataListener;
}
3. 在 app
中实现数据监听
在应用的 Application
类的初始化方法中,设置 LibAdDataListener
实现:
AdManager.getInstance(this).setSharedDataListener(new LibAdDataListener() {@Overridepublic boolean isVip() {// TODO: 调用 libVip 数据return false;}@Overridepublic String getVipType() {// TODO: 调用 libVip 数据return null;}
});
4. 在 libAd
中获取信息
当 libAd
需要获取 VIP 信息时,可以直接调用:
LibAdDataListener listener = AdManager.getInstance(context).getSharedDataListener();
通过这种方式,我们有效地解耦了 libAd
和 libVip
,同时利用 app
作为中介来实现数据共享。这种设计既避免了库之间的直接依赖,也遵循了合适的设计原则,使得系统更加灵活和可维护。
- 相关文章 Android:lib库之间互不依赖,怎么传值?
相关文章:
如何在 Android 项目中实现跨库传值
背景介绍 在一个复杂的 Android 项目中,我们通常会有多个库(lib),而主应用程序(app)依赖所有这些库。目前遇到的问题是,在这些库中,libAd 需要获取 libVip 的 VIP 等级状态…...
JavaCV之FFmpegFrameFilter视频转灰度
1、代码 package com.example.demo.ffpemg;import lombok.SneakyThrows; import org.bytedeco.javacv.*;public class FFmpegFrameFilterVideoExample {SneakyThrowspublic static void main(String[] args) {// 输入视频文件路径String inputVideoPath "f:/2222.mp4&qu…...

Redis:基于PubSub(发布/订阅)、Stream流实现消息队列
Redis - PubSub、Stream流 文章目录 Redis - PubSub、Stream流1.基于List的消息队列2.基于PubSub的消息队列3.基于Stream的消息队列1.Redis Streams简介2.Redis Streams基本命令1.XADD 添加消息到末尾2.XLEN 获取消息长度3.XREAD 读取消息 (单消费模式)4…...
C#飞行棋(新手简洁版)
我们要在主函数的顶部写一些全局静态字段 确保能在后续的静态方法中能够获取到这些值和修改 static int[] Maps new int[100];static string[] PlayerName new string[2];static int[] PlayerScore new int[2];static bool[] Flags new bool[2] {true,true }; static int[]…...

【OpenCV】图像转换
理论 傅立叶变换用于分析各种滤波器的频率特性。对于图像,使用 2D离散傅里叶变换(DFT) 查找频域。快速算法称为 快速傅立叶变换(FFT) 用于计算DFT。 Numpy中的傅立叶变换 首先,我们将看到如何使用Numpy查…...
力扣 重排链表-143
重排链表-143 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next)…...
【Kubernetes理论篇】容器集群管理系统Kubernetes(K8S)
Kubernetes集群部署基本管理实战 这么好的机会,还在等什么! 01、Kubernetes 概述 K8S是什么 K8S 的全称为 Kubernetes (K12345678S),PS:“嘛,写全称也太累了吧,写”。不如整个缩写 K8s 作为缩写的结果…...
Kubernetes 常用操作大全:全面掌握 K8s 基础与进阶命令
Kubernetes(简称 K8s)作为一种开源的容器编排工具,已经成为现代分布式系统中的标准。它的强大之处在于能够自动化应用程序的部署、扩展和管理。在使用 Kubernetes 的过程中,熟悉常用操作对于高效地管理集群资源至关重要。本文将详…...

爬虫基础之Web网页基础
网页的组成 网页可以分为三大部分–HTML、CSS 和 JavaScript。如果把网页比作一个人,那么 HTML 相当于骨架、JavaScript 相当于肌肉、CSS 相当于皮肤,这三者结合起来才能形成一个完善的网页。下面我们分别介绍一下这三部分的功能。 HTML HTML(Hypertext…...

k8s, deployment
控制循环(control loop) for {实际状态 : 获取集群中对象X的实际状态(Actual State)期望状态 : 获取集群中对象X的期望状态(Desired State)if 实际状态 期望状态{什么都不做} else {执行编排动作…...

使用ensp搭建OSPF+BGP和静态路由,底层PC使用dhcp,实现PC互通
1.4种方式,实现PC2可以互通底层的所有设备 OSPF:OSPF是一种用于互联网协议网络的链路状态路由协议 BGP:是一种用于互联网上进行路由和可达性信息传递的外部网关协议(EGP) 静态路由: 静态路由是一种路由方…...

TÜLU 3: Pushing Frontiers in Open Language Model Post-Training
基本信息 📝 原文链接: https://arxiv.org/abs/2411.15124👥 作者: Nathan Lambert, Jacob Morrison, Valentina Pyatkin, Shengyi Huang, Hamish Ivison, Faeze Brahman, Lester James V. Miranda, Alisa Liu, Nouha Dziri, Shane Lyu, Yuling Gu, Sau…...
深入解读 MySQL EXPLAIN 与索引优化实践
MySQL 是当今最流行的关系型数据库之一,为了提升查询性能,合理使用 EXPLAIN 工具和优化索引显得尤为重要。本文将结合实际示例,探讨如何利用 EXPLAIN 分析查询执行计划,并分享索引优化的最佳实践。 一、EXPLAIN 工具简介 EXPLAIN …...

Flume——进阶(agent特性+三种结构:串联,多路复用,聚合)
目录 agent特性ChannelSelector描述: SinkProcessor描述: 串联架构结构图解定义与描述配置示例Flume1(监测端node1)Flume3(接收端node3)启动方式 复制和多路复用结构图解定义描述配置示例node1node2node3启…...

ragflow连ollama时出现的Bug
ragflow和ollama连接后,已经添加了两个模型但是ragflow仍然一直warn:Please add both embedding model and LLM in Settings > Model providers firstly.这里可能是我一开始拉取的镜像容器太小,容不下当前添加的模型,导…...
基于centos7.7编译Redis6.0
背景: OS:CentOs 7.7 Redis: 6.0.6 编译构建报错如下: In file included from server.c:30:0: server.h:1044:5: error: expected specifier-qualifier-list before ‘_Atomic’_Atomic unsigned int lruclock; /* Clock for LRU eviction …...

uni-app项目无法在Android Studio模拟器上运行
目录 1 问题描述2 尝试解决3 引发原因4 解决方法4.1 换用 MuMu 模拟器 5 结语 1 问题描述 在使用 uni-app 开发 Pad 端 App 时,初始化项目后打算先运行一下确保初始化正常。打开 Android Studio 模拟器后,然后在 HbuilderX 中选择使用 App 标准基座 运…...
第一部分:Linux系统(基础及命令)
Linux操作系统的实操性非常强,纯操作,不适用于日常的办公使用 1.初始Linux 1.1 操作系统概述 1.1.1 了解OS的作用 OS:是计算机软件的一种,主要负责:作为用户和计算机硬件之间的桥梁,调度和管理计算机硬…...
No module named ‘_ssl‘ No module named ‘_ctypes‘
如果你使用的是基于 yum 的 Linux 发行版(例如 CentOS、RHEL、Fedora),安装 libc6-dev 的方式稍有不同。在这些系统中,通常对应的包是 glibc-devel。 No module named ‘_ctypes’ 使用 yum 安装 glibc-devel 更新系统的软件包列…...

【QT】编写第一个 QT 程序 对象树 Qt 编程事项 内存泄露问题
目录 1. 编写第一个 QT 程序 1.1 使用 标签 实现 🐇 图形化界面实现 🐇 纯代码形式实现 1.2 使用 按钮 实现 🐋 图形化界面实现 🐋 纯代码形式实现 1.3 使用 编辑框 实现 🥝 图形化界面实现 ᾕ…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...