前言
目前安卓开发一般都是用的mvvm模式,Jetpack的ViewModel是必不可少的一部分,而vm的生命周期要比Activity和Fragment长的,所以其一般不推荐其直接持有A或F,因为可能会造成内存泄漏的问题,但是不传入,Context的获取和显示网络加载弹窗又成了问题.
正文
首先解决显示网络加载弹窗的问题,其有两种方案:
1.使用MutableLiveData
首先我们在BaseViewModel中加入弹窗的MutableLiveData
val dialogShow = MutableLiveData(false)
然后我们可以在A或F的onCreate中获取vm的时候注册dialogShow的变化监听
val vm = ViewModelProvider(this).get(BaseViewModel::class.java)
vm.dialogShow.observe(this) { isShow ->
if (isShow) showWaitDialog() else dismissWaitDialog()
}
但是这样写太麻烦了,可以使用Kotlin的代理来简单实现,这样不仅声明的更方便,且自动注册了观察者
inline fun <reified VM : BaseViewModel> BaseActivity.baseViewModel() = lazy {
val vm = ViewModelProvider(this).get(VM::class.java)
vm.dialogShow.observe(this) { isShow ->
if (isShow) showWaitDialog() else dismissWaitDialog()
}
vm
}
//Activity中
val vm by baseViewModel<BaseViewModel>()
这样的优点很明显,vm完全不用持有A或F,但缺点是无法拿到A的Context
2.将BaseActivity或BaseFragment传入vm(废弃)
就像AndroidViewModel一样,将A传入vm,但有的小伙伴可能会问了,那内存泄漏了怎么办?办法很简单,等下次重建回来的时候替换掉已经销毁的A即可,实现方式如下(示例为A,F也类似)
open class BaseViewModel(
var baseActivity: BaseActivity//内部用于弹窗等的引用
) : ViewModel(){
fun getContext() = baseActivity
fun showWaitDialog(s: String?) = baseActivity.showWaitDialog(s)
fun dismissWaitDialog() = baseActivity.dismissWaitDialog()
}
//快捷获取BaseViewModel
inline fun <reified VM : BaseViewModel> BaseActivity.baseViewModel(
factory: ViewModelProvider.Factory? = null
) = lazy {
val vm = ViewModelProvider(
this,
factory ?: BaseViewModelFactory(this@baseViewModel)
).get(VM::class.java)
vm.baseActivity = this
vm
}
class BaseViewModelFactory(private val baseActivity: BaseActivity) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(BaseActivity::class.java).newInstance(baseActivity)
}
}
//Activity中
val vm by baseViewModel<BaseViewModel>()
这样在A的每个对象中第一次使用vm的时候就会把baseActivity替换为自身,也就不存在内存泄漏的问题了
这样就可以愉快的在vm中使用网络加载弹窗和获取Context了
对Kotlin或KMP感兴趣的同学可以进Q群 101786950
如果这篇文章对您有帮助的话
可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)