如何在 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 使用 编辑框 实现 🥝 图形化界面实现 ᾕ…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
