Mau*_*ycy 11 kotlin kotlin-multiplatform
我有一个管理器类,它有一个 Android 和 iOS impl(来自第 3 方库)。“例如 MyManagerImpl()”。为了构建第 3 方管理器,iOS 不需要 Context,但 Android 需要。我创建了一个公共类“MyManager”,它提取了需要在 commonMain 中调用的所有公共方法。
//commonMain
expect class MyManager {
fun method1()
companion object Factory {
makeManager(): MyManager
}
}
val manager = MyManager.Factory.makeManager() // ex intended usage
//androidMain
MyManagerImpl(context: Context) {
fun method1()
}
actual class MyManager private constructor(manager: MyManagerImpl) {
..
actual companion object Factory {
override fun makeManager(): MyManager {
return MyManager(MyManagerImpl(?how to get context?))
}
}
}
//iosMain
MyManagerImpl() {
fun method1()
}
actual class MyManager private constructor(manager: MyManagerImpl) {
..
actual companion object Factory {
override fun makeManager(): MyManager {
return MyManager(MyManagerImpl())
}
}
}
Run Code Online (Sandbox Code Playgroud)
合并两个实现的最干净的方法是什么?即使它们具有不同的构造函数依赖项,是否可以这样做?我们希望能够在 commonMain 中惰性地构造类。这可能吗?
我对 SQLDelight 也有同样的问题SqlDriver
,它需要 Android 上的上下文,但在 iOS 上不需要。使用 Kodein-DI 或 Koin,可以通过使用上下文注入来完成此操作,而无需任何混乱的静态变量。
基本概念是expect/actual用于创建特定于平台的工厂类(ManagerFactory
)。
在Android上,actual
实现ManagerFactory
将上下文作为参数,可以从DI上下文中获取(对于Android上的Kodein-DI,请参阅代码androidXModule
和文档)。
一旦在 android 和 iOS DI 模块中定义了工厂类,就可以在公共模块中注入/检索它,并将检索到的实例MyManager
绑定到 DI 中,并在需要的地方使用。
使用 Kodein-DI 看起来像这样:
//commonMain
expect class ManagerFactory {
fun createManager(): MyManager
}
val sharedModule = DI.Module("common") {
bind<MyManager>() with singleton { instance<ManagerFactory>().createManager() }
// now you can inject MyManager wherever...
}
Run Code Online (Sandbox Code Playgroud)
//androidMain
actual class ManagerFactory(private val context: Context) {
actual fun createManager(): MyManager = MyAndroidManagerImpl(context)
}
val androidModule = DI.Module("android") {
importAll(sharedModule)
// instance<Context> via androidXModule, see `MainApplication` below
bind<ManagerFactory>() with singleton { ManagerFactory(instance<Context>()) }
}
class MainApplication : Application(), DIAware {
override val di by DI.lazy {
// androidXModule (part of Kodein's android support library) gives us access to the context, as well as a lot of other Android services
// see https://github.com/Kodein-Framework/Kodein-DI/blob/7.1/framework/android/kodein-di-framework-android-core/src/main/java/org/kodein/di/android/module.kt
import(androidXModule(this@MainApplication))
importAll(androidModule)
}
}
Run Code Online (Sandbox Code Playgroud)
//iosMain
actual class ManagerFactory {
actual fun createManager(): MyManager = MyNativeManagerImpl()
}
val iosModule = DI.Module("ios") {
importAll(sharedModule)
bind<ManagerFactory>() with singleton { ManagerFactory() }
}
Run Code Online (Sandbox Code Playgroud)
一般来说,没有一种超级干净的方法可以做到这一点。没有办法只Context
从 Android 全局获取 a。虽然不漂亮,但我会做这样的事情:
//androidMain
class MyManagerImpl(context: Context) {
fun method1(){}
}
actual class MyManager private constructor(manager: MyManagerImpl) {
actual companion object Factory {
lateinit var factoryContxet :Context
override fun makeManager(): MyManager {
return MyManager(MyManagerImpl(factoryContxet))
}
}
}
class SampleApplication : Application{
override fun onCreate() {
super.onCreate()
MyManager.Factory.factoryContxet = this
}
}
Run Code Online (Sandbox Code Playgroud)
如果您希望能够从任何代码调用此函数,请Context
在应用程序启动时进行初始化。将其保留在静态参考中不会出现在每个人的最佳实践列表中,但这并不是一个技术问题。或者,您可以使用 执行类似的操作Activity
,但这有它自己的一系列问题。
归档时间: |
|
查看次数: |
4845 次 |
最近记录: |