android - 使用 kodein 在 ViewModelFactory 中注入(inject)保存的状态

标签 android kotlin mvvm dependency-injection kodein

我用 MVVM 模式开发应用程序。我想在用户旋转屏幕时保存 UI。

MyViewModel.kt

class MyViewModel(val repository: SomeRepository,
                       state : SavedStateHandle) : ViewModel() {

    private val savedStateHandle = state
    companion object {
        const val KEY = "KEY"
    }

    fun saveCityId(cityId: String) {
        savedStateHandle.set(CITY_KEY, cityId)
    }

    fun getCityId(): String? {
        return savedStateHandle.get(CITY_KEY)
    }

}

ViewModelFactory.kt
@Suppress("UNCHECKED_CAST")
class ViewModelFactory(
    private val repository: SomeRepository,
    private val state: SavedStateHandle
) : ViewModelProvider.NewInstanceFactory() {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MyViewModel(repository,state) as T
    }

}

我在 MainActivity 中调用它
MainActivity.kt
class MainActivity: AppCompatActivity(), KodeinAware {
    private val factory: ViewModelFactoryby instance()
    override val kodein by kodein()
    private lateinit var viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    cityId = intent.getStringExtra("cityId") ?: viewModel.getCityId()
        if (cityId != null) {
            viewModel.saveCityId(cityId!!)
            viewModel.getCurrentWeather(cityId!!)
        }
}

在这里我注入(inject)依赖项

申请.kt
class ForecastApplication: Application(), KodeinAware {
    override val kodein = Kodein.lazy {
        import(androidXModule(this@ForecastApplication))

        bind<SomeApi>() with singleton {
            Retrofit.create()
        }

        bind<WeatherRepository>() with singleton {
            WeatherRepository(instance())
        }
        bind() from provider {
            WeatherViewModelFactory(
                instance(), instance()
            )
        }
}
}

我有这个错误
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simpleforecast/com.example.simpleapp.UI.Cities.Activity}:org.kodein.di.Kodein$NotFoundException: No binding found for bind<SavedStateHandle>() 
with ?<Activity>().? { ? }


我应该如何构建 ViewModelFactory 并为 ViewModel 注入(inject) Saved State 模块?

最佳答案

SavedStateHandle是不能绑定(bind)到 DI 图的参数,因为它是从 Fragment 检索的(或 Activity ),因此您需要执行几个步骤才能使其工作:

1) DI viewmodel 定义 - 因为你有自定义参数,你需要使用 from factory :

bind() from factory { handle: SavedStateHandle ->
    WeatherViewModel(
        state = handle,
        repository = instance()
    )
}

2) ViewModel Factory - 您需要从 AbstractSavedStateViewModelFactory 继承

val vmFactory = object : AbstractSavedStateViewModelFactory(this, arguments) {
    override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
        val vmFactory: ((SavedStateHandle) -> WeatherViewModel) = kodein.direct.factory()
        return vmFactory(handle) as T
    }
}
create的内部从 DI 图中检索工厂的方法(从步骤 1 开始)。

3)您使用指定的工厂检索 ViewModel:
lateinit var vm : WeatherViewModel

fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    vm = ViewModelProvider(this, vmFactory)[WeatherViewModel::class.java]
}

或安卓 KTX 方式:
val vm : WeatherViewModel by viewModels { vmFactory }

关于android - 使用 kodein 在 ViewModelFactory 中注入(inject)保存的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60762599/

相关文章:

android - 将数据从 BroadcastReceiver 发送到 ViewModel

wpf - WPF:如何在运行时更改行为?

Android 工具和平台工具文件夹消失了

android - DrawerLayout 打开缓慢

android - Android 中的处理程序和内存泄漏

events - 如何查询 Kendo Tree 和 MVVM 模型?

WPF MVVM 对话框示例

android - Gradle:发布ApkProductionRelease到内部测试

java - EBean增强专家

Java DatagramSocket 无法接收所有数据包