你若需要时间,还得自己把他造出来。 喝汤能补 (* ^ ▽ ^ *)
前言
该文章作为学习交流,如有错误欢迎各位大佬指正 (* ^ ▽ ^ *)
- 本文简介
主要讲解:LiveData的使用,以及相关API的使用。 - 相关内容:
ViewModel使用 https://blog.csdn.net/qq_36462112/article/details/11133603
概述
LiveData 是JetPack提供的一种响应式编程组件,可以包含任何类型的数据,并在数据发送变化时通知观察者。
- LiveData一般与ViewModel一起使用,也可单独用在其他地方。即,在Activity中,我们可以不用手动获取ViewModel中的数据来更新界面,而是当ViewModel中数据改变时,主动通知Activity。
- LiveData内部使用了Lifecycles组件来自我感知生命周期的变化,从而在Activity销毁时及时释放引用,避免产生内存泄漏
- 如果界面不可见状态(息屏,或者被其他Activity遮挡),LiveData数据发送了变化,也不会通知观察者,这也是依靠于Lifecycles组件。
- LiveData数据发送多次变化,当Activity恢复可见状态时,只有最新的那份数据才会通知给观察者,之前的数据都被丢弃了。
使用
依赖库
依赖库添与ViewModel的添加方式一样
基本使用
- 创建使用LiveData包含的数据
MutableLiveData 是一种可变的LiveData,LiveData是一种不可变的LiveData。它们使用的主要方法是:
getValue() 获取LiveData中包含的数据,如果数据为空,则会返回null值
setValue() 给LiveData设置数据
postValue() 在非主线程中,给LiveData设置数据
在实际使用中,因kotlin语法糖,可以直接通过.value的方式进行获取和赋值。
- 通过 LiveData对象的observe()绑定观察者
任何LiveData对象都可以调用它的observe()方法来观察数据的变化。
observe(LifecycleOwner owner, Observer<? super T> observer)
第一个参数:LifecycleOwner对象
第二个参数:Observer接口,当数据发送变化时,会回调该接口中的onChanged()方法
-
LifecycleOwner 我们可以手动创建,但只要Activity是继承AppCompatActivity的,或者Fragment是继承 androidx.fragment.app.Fragment 的,其本身就是一个LifecycleOwner实例,这时因为AndroidX库已经自动完成了。
-
扩展:这里的Observer是一个单抽象方法接口参数,但是在低版本的库中不能使用函数式API写法的原因是:第一个参数LifecycleOwner也是一个单抽象方法接口;同时接受两个这样的参数时,要么都使用函数式API方式的,要么都不使用。由于第一个参数时this,所以第二参数无法使用。 但是在lifecycle-extensions:2.2.0中,对该方法进行了扩展,所以第二个参数可以用函数式API方式的
简单例子
这里以一个小功能进行使用演示,功能是:点击一次按钮,改变界面上的文字,以及重置文本内容的按钮。改变文本的逻辑均在ViewModel中完成。
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_live_data)
viewModel = ViewModelProviders.of(this, MainViewModelFactory("1¥"))
.get(MainViewModel::class.java)
btn_change.setOnClickListener {
viewModel.changeValue()
}
btn_reset.setOnClickListener {
viewModel.reset()
}
// 绑定观察者,当数据变化时,自动更新界面
viewModel.mText.observe(this, Observer { text ->
tv_content.text = text
})
}
}
class MainViewModel(textResume: String) : ViewModel() {
private var text = MutableLiveData<String>() //创建可变的LiveData类型的数据
val mText: LiveData<String> //创建不可变的LiveData类型的数据
get() = text
private var count = 0
private val textList = listOf("1¥","2¥","3¥")
init {
text.value = textResume
}
fun changeValue(){
count++
if (count > (textList.size - 1)){
count = 0
}
val str = text.value ?: "0¥"
text.value = textList[count] + " + " + str
}
fun reset(){
count = 0
text.value = "1¥"
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="change"/>
<Button
android:id="@+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reset"/>
</LinearLayout>
扩展:map与switchMap
当我们的项目变的越来越复杂时候,基本的时候一定是无法满足我们的业务场景的,可能需要进行某些转换操作,而LiveData也提供了通用的map与switchMap两种转换。
扩展:map
Map函数的使用场景:需要将某个LiveData对象转成任意其他类型的LiveData。
- Transformations.map(LiveData source , Function<X, Y> mapFunction)函数
用于将某个类型的LiveData转成任意其他类型的LiveData。
第一个参数:原始的LiveData对象
第二参数:一个转换函数,用于编写转换的逻辑 - 当数据发生变化的时候,map()函数会监听到变化并执行转换函数中的逻辑,然后再将转换后的数据通知给观察者。
大致的代码语法
Transformations.map(原始LiveData对象){
转化后的Livedata对象
}
简单示例:将Book的LiveData对象转为name的LiveData对象。
class Book {
var name:String = "自由"
var count:Int = 2
}
private val nameLiveData = MutableLiveData<Book>()
val name: LiveData<String> = Transformations.map(nameLiveData){ user->
user.name
}
扩展:switchMap
switchMap函数的使用场景比较固定:某个LiveData对象是调用另外的方法获取的时候。
- Transformations.switchMap(LiveData source , Function<X, Y> mapFunction)函数
用于如果某个LiveData对象是调用另外的方法获取的,那么可以将这个LiveData对象转换成另外一个可观察的LiveData对象。
第一个参数:原始的LiveData对象
第二参数:一个转换函数,用于编写转换的逻辑,在这个转换函数中必须返回一个LiveData对象 - 当数据发生变化的时候,switchMap()函数会监听到变化并执行转换函数中的逻辑,然后再将可观察的LiveData对象返回。
因为在另外的方法中,可能是直接新建的一个对象,如果我们直接在Activity中通过方法获取的LiveData对象的observe函数去监听,这样得到的对象永远都是老的LiveData实例,每次新的LiveData无法观察。
错误代码示范
object Repository {
fun getBook(name: String): LiveData<Book>{
val liveData = MutableLiveData<Book>()
liveData.value = Book(name)
return liveData
}
}
class MapViewModel : ViewModel() {
fun getBookName(name: String): LiveData<Book{
return Repository.getBook(name)
}
}
// 在Activity中进行绑定, 这种写法是错误的,无法获取到最新的Book类的信息
viewModelBook.getBookName("test").observe(this){ book ->
book.name
}
正确的方式
代码的效果,点击按钮,生成随机数字,并显示在界面上
class MainActivity : AppCompatActivity() {
lateinit var viewModelBook: MapViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_live_data)
btn_book.setOnClickListener {
val nunm = (0..100).random().toString()
viewModelBook.getBookName(nunm)
}
// 绑定观察者,当数据变化时,自动更新界面
viewModelBook.name2.observe(this, Observer { book ->
tv_name.text = book.name
})
class MapViewModel : ViewModel() {
private val mNameLiveData2 = MutableLiveData<String>()
val name2: LiveData<Book> = Transformations.switchMap(mNameLiveData2){ book ->
Repository.getBook(book)
}
fun getBookName(name: String) {
mNameLiveData2.value = name
}
}
object Repository {
fun getBook(name: String): LiveData<Book>{
val liveData = MutableLiveData<Book>()
liveData.value = Book(name)
return liveData
}
}
class Book(name: String) {
var name:String = name
var count:Int = 2
}
觉得有帮助的点下赞哟,毕竟三连步骤更多,嘻嘻,谢谢大家的支持(* ^ ▽ ^ *)