ViewModels(VM)理论上可以使用 Kotlin 扩展库 import androidx.fragment.app.viewModels 方法 by viewmodels() 初始化为类级实例变量。通过将 VM 初始化为类级别的实例 var,可以在类中访问它。
问题:将 VM 初始化为类级实例变量而不是在 onCreate 内部是否有缺点?
在使用onCreate 内的扩展函数创建 VM 时,VM 的范围仅在 onCreate 内,并且需要额外的代码来重新分配类级实例变量。
查看文档
将 VM 初始化为类实例 Val
class Fragment : Fragment() {
private val viewModel: SomeViewModel by viewModels()
private fun observeViewState() {
viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
//viewState used here.
}
}
}
在 onCreate 中初始化 VM 并重新分配类实例 Var
class Fragment : Fragment() {
private lateinit var viewModel: SomeViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel: ContentViewModel by viewModels()
this.viewModel = viewModel
}
private fun observeViewState() {
viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
//viewState used here.
}
}
}
传递参数/参数
// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
}
class SomeViewModel(private val someString: String) : ViewModel() {
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory("someString") }
}
使用参数/参数启用 SavedState
class SomeViewModelFactory(
private val owner: SavedStateRegistryOwner,
private val someString: String) : AbstractSavedStateViewModelFactory(owner, null) {
override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
SomeViewModel(state, someString) as T
}
class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel() {
val feedPosition = state.get<Int>(FEED_POSITION_KEY).let { position ->
if (position == null) 0 else position
}
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
fun saveFeedPosition(position: Int) {
state.set(FEED_POSITION_KEY, position)
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory(this, "someString") }
private var feedPosition: Int = 0
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
.findFirstVisibleItemPosition())
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
feedPosition = someViewModel.feedPosition
}
}