Android Kotlin 依赖注入全解:Koin appModule 配置与多 ViewModel 数据共享实战指南

一、基础配置与概念

1. 什么是 appModule

appModule 是 Koin 依赖注入框架中的核心配置模块,用于集中管理应用中的所有依赖项。它本质上是一个 Koin 模块(org.koin.core.module.Module),通过 DSL 方式声明各种组件的创建方式和依赖关系。

2. 基本结构

val appModule = module {// 在这里声明各种依赖项single { } // 单例组件factory { } // 每次创建新实例viewModel { } // ViewModel组件
}

二、完整配置示例

1. 基础配置(app/build.gradle)

dependencies {// Koin 核心implementation "io.insert-koin:koin-core:3.4.3"implementation "io.insert-koin:koin-android:3.4.3"// ViewModelimplementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"// 协程implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"
}

2. 完整 appModule 示例

// di/KoinModules.kt
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.moduleval appModule = module {// 1. 单例组件single { SharedPreferencesManager(androidContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE)) }// 2. 带接口绑定的Repositorysingle<UserRepository> { UserRepositoryImpl(get()) }// 3. ViewModelviewModel { MainViewModel(get(), get()) }// 4. 带参数的ViewModelviewModel { (userId: String) -> UserDetailViewModel(userId, get()) }// 5. 网络服务single {Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}// 6. 协程Dispatchersingle(named("IO")) { Dispatchers.IO }single(named("Main")) { Dispatchers.Main }
}

三、实战应用

1. Application 初始化

// MyApp.kt
class MyApp : Application() {override fun onCreate() {super.onCreate()startKoin {androidContext(this@MyApp)modules(appModule)// 调试日志if (BuildConfig.DEBUG) {androidLogger(Level.DEBUG)}}}
}

2. 在 Activity 中使用

class MainActivity : AppCompatActivity() {// 普通ViewModel注入private val mainViewModel: MainViewModel by viewModel()// 带参数的ViewModelprivate val userViewModel: UserDetailViewModel by viewModel { parametersOf(intent.getStringExtra("USER_ID") ?: "") }override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 直接使用已注入的ViewModelmainViewModel.loadData()}
}

3. 在 Fragment 中使用

class UserFragment : Fragment() {// 共享Activity的ViewModelprivate val sharedViewModel: MainViewModel by sharedViewModel()// 本Fragment独有的ViewModelprivate val userViewModel: UserViewModel by viewModel()
}

四、高级用法

1. 多模块组织

// di/modules/
val networkModule = module {single { createOkHttpClient() }single { createRetrofit(get()) }single { get<Retrofit>().create(ApiService::class.java) }
}val databaseModule = module {single { createDatabase(androidContext()) }single { get<AppDatabase>().userDao() }
}val repositoryModule = module {single<UserRepository> { UserRepositoryImpl(get(), get()) }
}val viewModelModule = module {viewModel { MainViewModel(get()) }
}

2. 作用域控制

val sessionModule = module {// 用户会话期间有效的作用域scope(named("SessionScope")) {scoped { UserSessionManager(get()) }}
}// 使用
class LoginActivity : AppCompatActivity() {private val sessionScope = getKoin().createScope("user_session", named("SessionScope"))private val sessionManager: UserSessionManager by inject()override fun onDestroy() {sessionScope.close()super.onDestroy()}
}

3. 属性注入

val configModule = module {single { AppConfig(apiUrl = getProperty("API_URL", "https://default.api"),timeout = getProperty("TIMEOUT_MS", 5000L))}
}// 在启动时加载属性
startKoin {androidContext(this@MyApp)modules(configModule)fileProperties("/config.properties") // 从assets加载
}

五、测试方案

1. 测试模块配置

val testModule = module {// 覆盖正式实现single<ApiService>(override = true) { MockApiService() }single<Database>(override = true) { InMemoryDatabase() }
}@Before
fun setup() {startKoin {modules(testModule)}
}@After
fun tearDown() {stopKoin()
}

2. ViewModel 测试

class MainViewModelTest {private lateinit var viewModel: MainViewModel@Beforefun setup() {val testModule = module {viewModel { MainViewModel(get()) }single<UserRepository> { FakeUserRepository() }}startKoin { modules(testModule) }viewModel = get()}@Testfun testLoadData() = runTest {viewModel.loadData()assertEquals(3, viewModel.users.value?.size)}
}

六、最佳实践

  1. 模块化组织

    • 按功能拆分模块(network/database/repository等)
    • 每个模块文件不超过200行
  2. 依赖顺序

    startKoin {modules(coreModule,      // 基础组件networkModule,   // 网络层databaseModule,  // 数据层viewModelModule  // 最后加载ViewModel)
    }
    
  3. 生命周期管理

    • 单例用于全局服务
    • factory用于无状态工具类
    • viewModel严格遵循生命周期
  4. 命名规范

    single(named("AuthApi")) { createAuthApi(get()) }
    single(named("PublicApi")) { createPublicApi(get()) }// 使用处
    class MyViewModel(@Named("AuthApi") private val authApi: ApiService,@Named("PublicApi") private val publicApi: ApiService
    ) : ViewModel()
    

七、常见问题解决

问题1:循环依赖

错误示例

class A(val b: B)
class B(val a: A)

解决方案

  • 使用 lazy 延迟初始化
  • 重构设计,引入第三方类

问题2:依赖找不到

检查步骤

  1. 确认模块已正确加载
  2. 检查 get() 参数类型是否匹配
  3. 查看 Koin 日志:
    startKoin {androidLogger(Level.DEBUG)
    }
    

问题3:内存泄漏

预防措施

// Fragment中正确使用
private val viewModel by viewModels<MyViewModel>()// 避免在Application中持有Activity引用

通过以上配置和实践,你可以构建出清晰、可维护的Android应用依赖注入体系。Koin的appModule让依赖管理变得直观且类型安全,特别适合Kotlin开发的Android项目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习记录:DAY21

我的开发日志&#xff1a;类路径扫描、DI 容器与动态代理 前言 我失忆了&#xff0c;完全不记得自己早上干了什么。 日程 早上 10 点左右开始&#xff0c;学了一早上&#xff0c;主要是类路径扫描相关的调试。 晚上 8 点了&#xff0c;真不能再摸&#x1f41f;了。 学习记录 计…

【Agent】MCP协议 | 用高德MCP Server制作旅游攻略

note MCP (Model Context Protocol) 代表了 AI 与外部工具和数据交互的标准建立。MCP 的本质&#xff1a;它是一个统一的协议标准&#xff0c;使 AI 模型能够以一致的方式连接各种数据源和工具&#xff0c;类似于 AI 世界的"USB-C"接口。 它能够在 LLM/AI Agent 与外…

使用 Spring Data Redis 实现 Redis 数据存储详解

使用 Spring Data Redis 实现 Redis 数据存储详解 Spring Data Redis 是 Spring 生态中操作 Redis 的核心模块&#xff0c;它封装了 Redis 客户端的底层细节&#xff08;如 Jedis 或 Lettuce&#xff09;&#xff0c;提供了统一的 API 来操作 Redis 的数据结构。以下是详细实现…

Qt5与现代OpenGL学习(四)X轴方向旋转60度

把上面两张图像放到D盘1文件夹内&#xff1a; shader.h #ifndef SHADER_H #define SHADER_H#include <QDebug> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QString>class Shader { public:Shader(const QString& verte…

【Machine Learning Q and AI 读书笔记】- 02 自监督学习

Machine Learning Q and AI 中文译名 大模型技术30讲&#xff0c;主要总结了大模型相关的技术要点&#xff0c;结合学术和工程化&#xff0c;对LLM从业者来说&#xff0c;是一份非常好的学习实践技术地图. 本文是Machine Learning Q and AI 读书笔记的第2篇&#xff0c;对应原…

using var connection = connectionFactory.CreateConnection(); using var 是什么意思

在 .NET 中&#xff0c;​​垃圾回收&#xff08;Garbage Collection, GC&#xff09;​​ 确实是自动管理内存的机制&#xff0c;但它 ​​仅适用于托管资源&#xff08;Managed Resources&#xff09;​​&#xff08;如类实例、数组等&#xff09;。然而&#xff0c;对于 ​…

Multicore-TSNE

文章目录 TSNE使用scikit-learn库使用Multicore-TSNE库安装方法基本使用方法采用不同的距离度量 其他资料 TSNE t-Distributed Stochastic Neighbor Embedding (t-SNE) 是一种高维数据的降维方法&#xff0c;由Laurens van der Maaten和Geoffrey Hinton于2008年提出&#xff0…

SI5338-EVB Usage Guide(LVPECL、LVDS、HCSL、CMOS、SSTL、HSTL)

目录 1. 简介 1.1 EVB 介绍 1.2 Si5338 Block Diagram 2. EVB 详解 2.1 实物图 2.2 基本配置 2.2.1 Universal Pin 2.2.2 IIC I/F 2.2.3 Input Clocks 2.2.4 Output Frequencies 2.2.5 Output Driver 2.2.6 Freq and Phase Offset 2.2.7 Spread Spectrum 2.2.8 快…

Spring AI应用系列——基于OpenTelemetry实现大模型调用的可观测性实践

一、项目背景与目标 在AI应用日益复杂的今天&#xff0c;大模型服务&#xff08;如语言理解和生成&#xff09;的性能监控和问题排查变得尤为关键。为了实现对大模型调用链路的可观测性&#xff08;Observability&#xff09;管理&#xff0c;我们基于 Spring Boot Spring AI…

Spyglass:官方Hands-on Training(一)

相关阅读 Spyglasshttps://blog.csdn.net/weixin_45791458/category_12828934.html?spm1001.2014.3001.5482 本文是对Spyglass Hands-on Training中第一个实验的翻译&#xff08;有删改&#xff09;&#xff0c;Lab文件可以从以下链接获取。Spyglass Hands-on Traininghttps:…

PCB设计工艺规范(三)走线要求

走线要求 1.走线要求2.固定孔、安装孔、过孔要求3.基准点要求4.丝印要求 1.走线要求 印制板距板边距离:V-CUT 边大于 0.75mm&#xff0c;铣槽边大于0.3mm。为了保证 PCB 加工时不出现露铜的缺陷&#xff0c;要求所有的走线及铜箔距离板边:V-CUT边大于 0.75mm&#xff0c;铣槽边…

抓取工具Charles配置教程(mac电脑+ios手机)

mac电脑上的配置 1. 下载最新版本的Charles 2. 按照以下截图进行配置 2.1 端口号配置&#xff1a; 2.2 https配置 3. mac端证书配置 4. IOS手机端网络配置 4.1 先查看电脑上的配置 4.2 配置手机网络 连接和电脑同一个wifi&#xff0c;然后按照以下截图进行配置 5. 手机端证书…

【CSS】精通Flex布局(全)

目录 1. flex布局体验 1.1 传统布局 与 flex布局 1.2 初体验 2. flex布局原理 2.1 布局原理 3. flex布局父项常见属性 3.1 常见父项属性 3.2 属性值 3.3 justify-content 设置主轴上的子元素排列方式 3.4 flex-wrap设置子元素是否换行 3.5 align-items 设置侧轴上的…

力扣第447场周赛

这次终于赶上力扣的周赛了, 赛时成绩如下(依旧还是三题 )&#xff1a; 1. 统计被覆盖的建筑 给你一个正整数 n&#xff0c;表示一个 n x n 的城市&#xff0c;同时给定一个二维数组 buildings&#xff0c;其中 buildings[i] [x, y] 表示位于坐标 [x, y] 的一个 唯一 建筑。 如…

AI中常用概念的理解

1. RAG&#xff08;检索增强生成&#xff09; 通俗理解&#xff1a;就像你写作业时&#xff0c;先查课本 / 百度找资料&#xff0c;再根据资料写答案&#xff0c;而不是纯靠记忆瞎编。 AI 模型&#xff08;比如 ChatGPT&#xff09;回答问题时&#xff0c;先去 “数据库 / 互联…

SQLServer多版本兼容Java方案和数据采集

Maven引入 <dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>sqljdbc4</artifactId><version>4.0</version></dependency><dependency><groupId>net.sourceforge.jtds</groupId><ar…

【每日八股】复习 Redis Day4:线程模型

文章目录 复习 Redis Day4&#xff1a;线程模型介绍一下 Redis 的线程模型核心线程模型&#xff08;Redis 6.0 之前&#xff09;Redis 6.0 的多线程改进Redis 真的是单线程吗&#xff1f;Redis 的线程模型剖析 上一篇 Redis 的应用我今天才完成&#xff0c;因此明天一并复习 Re…

树莓派智能摄像头实战指南:基于TensorFlow Lite的端到端AI部署

引言&#xff1a;嵌入式AI的革新力量 在物联网与人工智能深度融合的今天&#xff0c;树莓派这一信用卡大小的计算机正在成为边缘计算的核心载体。本文将手把手教你打造一款基于TensorFlow Lite的低功耗智能监控设备&#xff0c;通过MobileNetV2模型实现实时物体检测&#xff0…

vs2019编译occ7.9.0时,出现fatal error C1060: compiler is out of heap space

问题描述 visual studio 2019编译opencascade 7.9.0时&#xff0c;出现编译错误 fatal error C1060: compiler is out of heap space 解决方案 修改vs2019并行编译的线程个数&#xff0c;默认是12个&#xff0c;我改成了4个&#xff0c;问题解决 Tools > Project and Sol…

vue跨域问题总结笔记

目录 一、Websocket跨域问题 1.nginx配置 2.VUE CLI代理 3.env.development配置 4.nginx日志 5.解决 一、解决跨域的几种常用方法 1.Vue CLI代理 2.JSONP 3.WebSocket 4.NGINX解决跨域问题 6.Java解决跨域 二、Vue跨域问题详解 1. 什么是跨域 2. 跨域的例子 3.…