1

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

我的视图模型.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!!)
        }
}

在这里我注入依赖项

应用程序.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 模块?

4

1 回答 1

3

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]
}

或安卓 KTX 方式:

val vm : WeatherViewModel by viewModels { vmFactory }
于 2020-03-30T19:49:37.937 回答