JetPack之ViewModel初识|青训营笔记
这是我参与[第四届青训营]笔记创作活动的第6天
前言
对于四大组件我们简单的认识了一下,接下来就让我们开始正式的Android组件学习吧!!
首先,我们先介绍一下ViewModel,它是谷歌推荐的Jetpack中最重要的组件之一,它的出现,从根本上减轻activity所负责的任务,它专门存放于用户界面相关的一些数据,表明只要你在界面上看到的数据,它的相关变量都存放在ViewModel中。它的最强特性就是让数据可在发生屏幕旋转等配置更改后继续留存。接下来我们就来一点点探究它,首先我们得导入依赖项可参考⬇️
ViewModel的生命周期
说道ViewModel的生命周期,那就一定得看这张图🔽
上图就是activity在经历屏幕旋转后结束时所处的各个生命周期状态,旁边的就是ViewModel的生命周期了。大家可以发现,ViewModel的生命周期会比activity的生命周期来的更长,在感知到activity完成其任务后ViewModel才被清除,大家可以思考一下,它是怎么做到的❓
其实它是依靠着Lifecycle这一对象去感知其存在时间,而什么时间消失则是,Activity 完成时、 Fragment 分离时。进而影响着ViewModel的存在时间。对其感兴趣深究下去的同学可以参考官方文档,我就不再这过多说明了😆
ViewModel实现方式
接下来我们就来看看如何使用ViewModel为界面准备数据吧❗️
- Activity
首先我们先简单创建好一个ViewModel的类
class MainViewModel : ViewModel() {
//A分数
var scoreA = 0;
//B分数
var scoreB = 0;
}
//Activity
class MainActivity : AppCompatActivity(),View.OnClickListener{
private val TAG = "ViewModelActivity"
private lateinit var binding:ActivityMainBinding
lateinit var model: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//绑定viewModel
model = ViewModelProvider(this)[MainViewModel::class.java]
binding.btnReset.setOnClickListener(this)
binding.btnThreeA.setOnClickListener(this)
binding.btnThreeB.setOnClickListener(this)
binding.btnTwoA.setOnClickListener(this)
binding.btnTwoB.setOnClickListener(this)
binding.aScore.text = "${model.scoreA}"
binding.bScore.text = "${model.scoreB}"
}
override fun onClick(v: View?) {
when(v){
binding.btnThreeA -> {
model.scoreA = model.scoreA + 3
binding.aScore.text = "${model.scoreA}"
Log.d(TAG, "onCreateA: " + model.scoreA)
}
binding.btnThreeB -> {
model.scoreB += 3
binding.bScore.text = "${model.scoreB}"
Log.d(TAG, "onCreateB: " + model.scoreB)
}
binding.btnTwoA ->{
model.scoreA = model.scoreA + 2
binding.aScore.text = "${model.scoreA}"
Log.d(TAG, "onCreateA: " + model.scoreA)
}
binding.btnTwoB -> {
model.scoreB += 2
binding.bScore.text = "${model.scoreB}"
Log.d(TAG, "onCreateB: " + model.scoreB)
}
binding.btnReset ->{
model.scoreA = 0
model.scoreB = 0
binding.aScore.text = "${model.scoreA}"
binding.bScore.text = "${model.scoreB}"
Log.d(TAG, "onCreateB: " + model.scoreB)
Log.d(TAG, "onCreateA: " + model.scoreA)
}
else -> null
}
}
}
可以看到点击不同的按钮产生的数字变化如下
接下来我们选择一下屏幕,可以知道屏幕旋转后,其显示的数字并未发生改变。
- Fragment
在activity中感受了ViewModel的魅力后,那接下来我们来说说fragment是如何去绑定viewModel的
//绑定方式同activity
val model = ViewModelProvider(requireActivity())[MainViewModel::class.java]
接着依旧旋转屏幕,效果跟旋转activity一样,没有差别,接着大家可多试试使用不同的fragment之间切换,来共享viewmodel的数据,可以参考官网,我就不再这里展示了
向ViewModel传递参数
了解了ViewModel的特性之后,接下来我们就试着向viewModel传递参数吧
我们复用一下上面的MainViewModel,在其构造函数中添加两个参数,如下
class MainViewModel(rescoreA:Int,rescoreB:Int) : ViewModel() {
//A分数
var scoreA = rescoreA;
//B分数
var scoreB = rescoreB;
}
接下来就是向其中传递参数了,我们可以新建一个ViewModelProviderFactory类去实现ViewModelProvider.Factory接口
class MainViewModelFactory(private val resoreA:Int,private val resoreB:Int) : ViewModelProvider.Factory {
//实现接口方法,返回viewModel对象
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(resoreA,resoreB) as T
}
}
//接着就是去获取了,也跟上面差不多
val viewModel = ViewModelProvider(this,MainViewModelFactory(resoreA = 1, resoreB = 2))[MainViewModel::class.java]
后面就靠大家自己去练习了,总体上大致相同,那大家可以思考一下,为啥要传递参数,它的应用场景在哪,其实有时候我们退出程序后,重新进入时,此时就可以调用这种方式来及时显示这些数据,不至于退出程序后,丢失。
最后
至此,viewModel就简单介绍完了,更详细的内容可参考一下官方文档,本文所写的是本人根据所参考资料,以及网上所学的个人见解,如有错误或者不恰当之处,欢迎私信我,加以改正!同时期待您的关注,感谢您的阅读,谢谢!