上手Jetpack:ViewModel以及LiveData

ViewModel

添加依赖

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

创建ViewModel

class StartViewModel: ViewModel() {
    
    
}

获取ViewModel实例

class StartActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val viewModel: StartViewModel = ViewModelProvider(this).get(StartViewModel::class.java)
    }
}

通过ktx库简化ViewModel实例的获取

首先添加ktx依赖

implementation "androidx.fragment:fragment-ktx:1.2.4"

然后获取ViewModel实例写法变这样

class StartActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val viewModel: StartViewModel by viewModels()
    }
}

向ViewModel传递参数

class StartViewModel(val param: String) : ViewModel() {
    
}

怎么获取了传递了参数的ViewModel实例?
通过实现ViewModelProvider.Factory接口,创建ViewModelFactory类

@Suppress("UNCHECKED_CAST")
class StartViewModelFactory(private val param: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return StartViewModel(param) as T
    }
}

LiveData

创建LiveData对象

val number = MutableLiveData<Int>()

读写LiveData对象的方法

getValue()、setValue()、postValue()

观察LiveData对象

viewModel.number.observe(this, Observer { number ->
            println(number)
        })

通过ktx让观察LiveData对象的写法看起来更舒服

首先添加依赖

implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"

然后观察LiveData对象的写法变成了这样

viewModel.number.observe(this) { number ->
            println(number)
        }

为了永远暴露给外部不可变的LiveData对象,更加推荐的写法

private val _number = MutableLiveData<Int>()

    val number: LiveData<Int> get() = _number

当外部调用number对象时,实际上获得的是_number的实例,但是无法给counter设置数据了

使用map将LiveData自由地转换成其它类型的LiveData

什么场景下用map?
比如有一个User对象,他有三个属性:name,age,sex,但是我在MainActivity中只用到了User里的name属性。

data class User(var name: String, var age: Int, var sex: String)
val user = MutableLiveData<User>()

val userLiveData = MutableLiveData<User>()
    
    val userName: LiveData<String> = Transformations.map(userLiveData) { user ->
        user.name
    }

使用swtichMap

使用场景:当ViewModel中的某个LiveData对象是调用另外的方法获取的

object Repository {

    fun getUser(userId: String): LiveData<User> {
        val liveData = MutableLiveData<User> ()
        liveData.value = User(userId, userId, 0)
        return liveData
    }
}

这里每次调用getUser方法都会返回一个新的LiveData对象

class StartViewModel(val param: String) : ViewModel() {

    fun getUser(userId: String): LiveData<User> {
        return Repository.getUser(userId)
    }
}

如果我们还是直接观察这个StartViewModel中的getUser方法返回的LvieData对象,显然是错误的,因为这个方法返回的是Repository中的getUser方法的返回值,但是Repository中的getUser方法返回的始终是一个新的LiveData对象,这样我们就无法观察到LiveData对象值的变化。(这个问题是很常见的,因为在官方推荐的MVVM架构中,我们的数据操作都是放到Repository层的)

使用switchMap解决这个问题

private val userIdLiveData = MutableLiveData<String>()

    var user: LiveData<User> = Transformations.switchMap(userIdLiveData) { userId ->
        Repository.getUser(userId)
    }

    fun getUser(userId: String) {
        userIdLiveData.value = userId
    }

这里swtichMap的工作流程
当Activity调用ViewModel中的getUser方法来获取用户数据时,将传入的userId设置到userLiveData中,一旦userLiveData的值发生变化,那么观察userIdLiveData的switchMap就会执行,去调用Repository.getUser()方法获取真正的用户数据,同时switchMap会将Repository.getUser()方法返回的LiveData对象转换成一个可观察的LIveData对象,Activity只需要去观察这个返回的user就可以了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值