在 Kotlin 中ViewModel 的获取及使用指南
目录
- 在 Kotlin 中,ViewModel 的获取
- Kotin- Fragment 获取 ViewModel 实例正确方式
- 1. 第一种获取方式:
- 2. 第二种获取方式
在 Kotlin 中,ViewModel 的获取
在 Kotlin 中,by viewModels() 和 by viewModels { } 都是用来在 Activity 或 Fragment 中获取 编程客栈ViewModel 实例的属性委托。它们之间的区别在于是否传递自定义的 ViewModelProvider.Factory:
by viewModels(): 使用默认的 ViewModelProvider.Factory,通常,这个默认工厂会使用 ViewModel 的无参构造函数来创建 ViewModel 实例。- 如果 ViewModel 没有参数,或者使用了依赖注入(如 Hilt)来提供 ViewModel,可以使用这种形式;
by viewModels {...}: 花括号内是一个 Lambda,用于提供自定义的 ViewModelProvider.Factory。当 ViewModel 需要参数时使用,必须提供自定义的 Factory 来创建 ViewModel 实例;
使用指南:
- 如果 ViewModel 不需要外部参数:使用
by viewModel(); - 如果 ViewModel 需要参数或依赖:使用
by viewModels { customFactory }; - 如果使用 Hilt/Dagger 等 DI 框架:使用
by viewModels()(框架自动处理);
添加依赖:
dependencies {
// 必需:ViewModel 核心
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
// 必需:Activity 或 Fragment 的委托支持(二选一或都选)
implementation "androidx.activity:activity-ktx:1.8.2" // Activity 中使用
implementation "androidx.fragment:fragment-ktx:1.6.2" // Fragment 中使用
}
例如:假设我们有一个需要参数的 ViewModel:
class MyViewModel(private val repository: MyRepository) : ViewModel() {
// ...
}
那么,在 Activity 或 Fragment 中,我们需要提供一个 Factory 来创建 MyViewModel:
private val viewModel: MyViewModel by viewModels {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
// 假设我们已经有了MyRepository的实例
return MyViewModel(myRepository) as T
}
}
}
或者,你可以定义一个 ViewModelFactory 类:
class MyViewModelFactory(private val repository: MyRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.Java)) {
@Suppress("UNCHECKED_CAST")
return MyViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
然后,在委托属性中使用:
private val viewModel: MyViewModel by viewModels {
MyViewModelFactory(myRepository)
}
补充:Kotin- Fragment 获取 ViewModel 实例正确方式
Kotin- Fragment 获取 ViewModel 实例正确方式
1. 第一种获取方式:
通常获取 ViewModel 方法:
val model : BlankViewModel by lazy{
ViewModelProvider(this,BlankViewModel.BlankViewModelFactory()).get(BlankViewModel::class.java)
}
//该方法已被废弃:viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
对应的 BlankViewModelFactory 方法
class BlankViewModel : ViewModel() {
// TODO: Implement the ViewModel
private val number = MutableLiveData<Int>();
private var i=0
fun getNumber() : LiveData<Int>{
return number
}
fun addNumber(){
i++
number.value = i
}
class BlankViewModelFactory(): ViewModelProvider.Factory{
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return BlankViewModel() as T
}
}
}
当我们创建 Fragment 页面,并将页面添加到一个 Activity 页面中时,想要实现在 Activity 中调用 ViewModel 中的方法使得 livedata 的数据改变,并希望 Fragment 页面也可以监听到变化,此时就需要获取到同一个 ViewModel 实例,才能保证两个页面的数据同时变化。
首先,在 Activity 中获取 BlankViewModel ,并通过点击按钮调用其中的 addNumber 方法,让变量+1
class FragmentActivity : AppCompatActivity() {
val model : BlankViewModel by lazy{
ViewModelProvider(this,BlankViewModel.BlankViewModelFactory()).get(BlankViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment)
val button = findViewById<Button>(R.id.add).setOnClickListener {
model.addNumber()
}
}
}
第一个 Fragment 页面:
class LeftFragment : Fragment() {
val model : BlankViewModel by lazy{
ViewModelProvider(requireActivity(),BlankViewModel.BlankViewModelFactory()).get(BlankViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.blank_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanandroidceState)
val left = view.findViewById<TextView>(R.id.left_tv)
model.getNumber().observe(requireActivity(), Observer {
Log.d("IT",""+it)
left.text = it.toString()
})
}
}
在获取 ViewModel 实例时,ViewModelProvider 中的第一个参数 ViewModelStoreOwner 对象传递的是requireActivity 方法,这个方法里就是获取当前的 Activity 实例 ;如果该位置仍然传 this ,则获取的是与 Activity 不同的 ViewModel 实例,这样 Activity 点击按钮时 Fragment 页面的数值并不会变化。
val model : BlankViewModel by lazy{
ViewModelProvider(requireActivity(),BlankViewModel.BlankViewModelFactory()).get(BlankViewModel::class.java)
}
在观察变化的方法中,也是同样的道理:
编程 model.getNumber().observe(requireActivity(), Observer {
left.text = it.toString()
})
另一个 Fragment 页面和它一样,这里就不添加了。
2. 第二种获取方式
通过ktx简化:
添加 ktx 依赖,这里要注意版本,我的 kotlin 版本过低,下载高版本会报红:implementation "androidx.fragment:fragment-ktx:1.2.5" implementation "androidx.activity:activity-ktx:1.0.0-alpha03"
在 Activity 页面中:
//这里省略掉其他部分 val model by viewModels<BlankViewModel>()
在 Fragment 页面中
//这里省略掉其他部分
val model by activityViewModels<BlankViewModel>()
//这里可以正常传this
model.getNuandroidmbandroider().observe(this, Observer {
Log.d("IT",""+it)
left.text = it.toString()
})
以上就是获取同一 ViewModel 实例的方法。如有不对,请指正。
到此这篇关于在 Kotlin 中ViewModel 的获取及使用指南的文章就介绍到这了,更多相关Kotlin ViewModel 获取内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
加载中,请稍侯......
精彩评论