【问题标题】:Inject Saved State in ViewModelFactory with kodein使用 kodein 在 ViewModelFactory 中注入保存的状态
【发布时间】:2020-06-30 21:47:43
【问题描述】:

我使用 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!!)
        }
}

我在这里注入依赖项

Application.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 注入 Saved State 模块?

【问题讨论】:

  • 在您的绑定中,您没有任何SavedStateHandle,因此instance() 函数无法为您猜出它。你的状态来自哪里?

标签: android kotlin mvvm dependency-injection kodein


【解决方案1】:

SavedStateHandle是不能绑定到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]
}

或android KTX方式:

val vm : WeatherViewModel by viewModels { vmFactory }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-06
    • 2020-04-20
    • 2016-11-29
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 2011-05-15
    • 2010-09-14
    相关资源
    最近更新 更多