如何在 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 使用 编辑框 实现 🥝 图形化界面实现 ᾕ…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
