如何在 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面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
