你需要懂的ViewModel那些事

3,590 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

本文主要讲解ViewModel的基本使用技巧

1.ViewModel构造函数支持传入Application

自定义一个ViewModel继承AndroidViewModel

class ApplicationViewModel(app: Application) : AndroidViewModel(app) {
    //获取Applicaction
    private val mApp: Application by lazy {
        getApplication()
    }
}

我们就可以在通过getApplication()方法获取Application。

2.ViewModel构造函数支持传入其他类型参数

ViewModel支持传入工厂类来创建具体的ViewModel类型,所以我们直接继承ViewModelProvider.Factory自定义一个工厂类,并在创建ViewModel的时候传入该自定义的工厂类。

比如下面我们支持MainViewModel的构造参数传入一个Int类型:

class CustomVMFactory(
    private val factory: ViewModelProvider.Factory,
    private val type: Int
) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(type) as T
        }
        return factory.create(modelClass)
    }
}

可以发现,我们自定义的CustomVMFactory工厂类还得传入一个Activity的默认工厂,以保证当我们自定义的工厂类无法创建ViewModel时交给原本Activity默认工厂进行处理,这就相当于一个兜底作用,本质上体现的是静态代理模式的一种实现。

使用如下:

private val mVM by viewModels<MainViewModel> {
    CustomVMFactory(
        defaultViewModelProviderFactory,
        5
    )
}

3.ViewModel中LiveData使用注意点

一般我们在ViewModel中这样定义LiveData:

//私有可变
private val data: MutableLiveData<Response<String>> = MutableLiveData()
//对外暴漏不可变
val data1: LiveData<Response<String>> = data

我们对外暴漏不可变的data1本质上是额外声明了一个成员变量和一个成员方法:

image.png

通过反编译代码来看,其实额外声明的属性根本没有必要,我们只需要getData1方法获取不可变的LiveData即可。

所以我们可以这样改造下:

//对外暴漏不可变
val data1: LiveData<String> get() = data

反编译看下效果:

image.png

通过反编译的代码可以看到,暴露不可变的LiveData只额外声明了一个方法,减少了一个额外属性的声明。

4.ViewModel中协程的使用

依赖implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"中为ViewModel提供了一个协程扩展属性:viewModelScope

image.png

我们就可以直接使用viewModelScope属性来执行耗时操作线程切换

fun request() {
    viewModelScope.launch(Dispatchers.IO) {
        //执行耗时代码,比如网络请求
    }
}