Android JetPack系列---ViewModel

接着上一篇博客Lifecycle,这一篇我们就来说一下ViewModel,jetpack全家桶系列之一

jetpack系列

第一篇:jetpack—Lifecycle的运用
第二篇:jetpack—ViewModel的了解
第三篇:jetpack—LiveData的使用
第四篇: JetPack系列—DataBinding的使用入门

ViewModel的作用是什么?
引用官话:ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

就像上面说的我们先举个例子
在这里插入图片描述
现在有一种情况就是,就用官话说的屏幕旋转的时候,比如我的界面上有个Textview,里面有一段文字1111111,然后点击以后变成了22222222,然后我旋转屏幕TextView就又变成了111111111,为什么呢?因为Activity在屏幕旋转的时候被销毁然后重新创建界面,那这个时候数据不就不对了嘛,有什么办法呢?对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。为了解决这种问题jetpack全家桶推出了ViewModel。
在这里插入图片描述
我们先看来看看情况 界面上有个Textview,里面有一段文字1111111,然后点击以后变成了22222222

class MainActivity : AppCompatActivity() {
    private lateinit var start: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        start = findViewById(R.id.start)

        val mydata: MyData = MyData()
        start.text = mydata.name
        start.setOnClickListener {
            mydata.name = "2222222"
            start.text = mydata.name
            startActivity(Intent(this,ViewModelActivity::class.java))
        }
    }
}

数据类

data class MyData(var name: String = "1111111111") {
}

结果上图
在这里插入图片描述
点击
在这里插入图片描述
旋转
在这里插入图片描述
结果就变了,道理都知道Activity在屏幕旋转的时候被销毁然后重新创建界面

开始改用ViewModel来改变
加入依赖

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"

先创建一个MyViewModel继承ViewModel

class MyViewModel : ViewModel() {
    var myData: MyData = MyData()

    fun getUserData(): String = myData.name

    fun setUserData(str: String) {
        myData.name = str
    }

    override fun onCleared() {
        super.onCleared()
        Log.e("MyViewModel", "onCleared")
    }
}

还是相同的操作

class MainActivity : AppCompatActivity() {
    private lateinit var start: TextView
 	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        start = findViewById(R.id.start)
        val model = ViewModelProvider(this)[MyViewModel::class.java]
        start.text = model.getUserData()
        start.setOnClickListener {
            model.setUserData("22222222")
            start.text = model.getUserData()
        }
    }
}

看结果
在这里插入图片描述
点击
在这里插入图片描述
旋转
在这里插入图片描述
数据没变ViewModel起作用了然后我们来分析一下原因
首先我们看见了自己写的ViewModel是通过ViewModelProvider来实例化的

val model = ViewModelProvider(this)[MyViewModel::class.java]

然后就只能看些ViewModelProvider的代码了从构造上可以看出需要我们给的是一个ViewModelStoreOwner这个对象,但是我们确给了一个this当前的Activity?
在这里插入图片描述
然后接着查看ViewModelStoreOwner你就会发现原来ComponentActivity实现了这个接口。这就可以知道为啥这个地方可以传当前的Activity进去了。
在这里插入图片描述
然后就可以看到ComponentActivity重写了ViewModelStoreOwner中间唯一的方法,并且返回了一个ViewModelStore。
在这里插入图片描述
点击去ViewModelStore你就可以看到我们都viewModel其实使用hashmap的形式被存放起来了
在这里插入图片描述
当页面需要的时候我们就会通过hashmap的key去查,有就会返回,没有就实例化一个,和界面的销毁重建没有任何牵连,所以不会导致viewModel的改变。

那什么时候viewModel的数据会改变呢?
可以看到之前我们自己写的代码MyViewModel重写了onCleared,在Activity屏幕进行旋转的时候,并不会调用这个方法,ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 activity,是在 activity 完成时;而对于 fragment,是在 fragment 分离时。
在这里插入图片描述
在 Fragment 之间共享数据
还是用上面的MyViewModel

class MyViewModel : ViewModel() {
    var myData: MyData = MyData()

    fun getUserData(): String = myData.name

    fun setUserData(str: String) {
        myData.name = str
    }

    override fun onCleared() {
        super.onCleared()
        Log.e("MyViewModel", "onCleared")
    }
}

普通的2个Fragment一个设置数据 另外一个可以直接获取到数据

class OneFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val model = ViewModelProvider(requireActivity())[MyViewModel::class.java]
        model.setUserData("fragment 数据共享")
    }
}
class TwoFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val model = ViewModelProvider(requireActivity())[MyViewModel::class.java]
        model.getUserData()
    }
}

但是的有一个前提,那就是依附于同一个activity,因为我们知道的是我们用的是hashmap储存的,他共同的一个key所以取出来的ViewModel才会是统一的,如果不是同一个Key那数据着不能共享。

总结
ViewModel可以更好的把数据从代码层分离开来,可以有效的防止因为Activity销毁重建带来的数据丢失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值