一、基礎配置與概念
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)}
}
六、最佳實踐
-
模塊化組織:
- 按功能拆分模塊(network/database/repository等)
- 每個模塊文件不超過200行
-
依賴順序:
startKoin {modules(coreModule, // 基礎組件networkModule, // 網絡層databaseModule, // 數據層viewModelModule // 最后加載ViewModel) }
-
生命周期管理:
- 單例用于全局服務
- factory用于無狀態工具類
- viewModel嚴格遵循生命周期
-
命名規范:
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:依賴找不到
檢查步驟:
- 確認模塊已正確加載
- 檢查 get() 參數類型是否匹配
- 查看 Koin 日志:
startKoin {androidLogger(Level.DEBUG) }
問題3:內存泄漏
預防措施:
// Fragment中正確使用
private val viewModel by viewModels<MyViewModel>()// 避免在Application中持有Activity引用
通過以上配置和實踐,你可以構建出清晰、可維護的Android應用依賴注入體系。Koin的appModule讓依賴管理變得直觀且類型安全,特別適合Kotlin開發的Android項目。