首先一个全局的ViewModel可以用来实现类似于EventBus的功能,在前台修改了一个数据之后,可通知给其他页面的监听,用来推动UI的改变,而不需要主动获取
举个栗子,可以用于在一个页面修改了用户的信息,然后通知其他页面去同步修改用户信息
首先,考虑到多个Module,可以下沉一个最深mudule的BaseApplication,然后再里面实现一个ViewModelProvider的功能(这里是直接写在主Module,毕竟我只有一个Module)
class RaiseSalaryApplication : Application(),ViewModelStoreOwner {
private lateinit var appViewModelStory: ViewModelStore
private var appViewModelFactory: ViewModelProvider.Factory? = null
override fun onCreate() {
super.onCreate()
appViewModelStory = ViewModelStore()
}
override fun getViewModelStore(): ViewModelStore {
return appViewModelStory
}
/**
* 创建一个全局的ViewModelProvider
*/
fun getApplicationViewModel():ViewModelProvider{
return ViewModelProvider(this,this.getApplicationViewModelFactory())
}
private fun getApplicationViewModelFactory():ViewModelProvider.Factory{
if (appViewModelFactory == null){
appViewModelFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
}
return appViewModelFactory as ViewModelProvider.Factory
}
}
然后在Manifest.xml文件中注册
之后再使用kotlin的一个特征 --- 扩展函数
创建一个文件ViewModelKtx.kt
/**
* Activity中获取一个全局的ViewModel,如果没有,则会创建
*/
inline fun <reified VM : ViewModel> AppCompatActivity.getAppViewModel(): VM {
(this.application as? RaiseSalaryApplication).let {
if (it == null) {
throw NullPointerException("未注册Application,无法使用getAppViewModel方法")
} else {
return it.getApplicationViewModel()[VM::class.java]
}
}
}
/**
* Fragment中获取一个全局的ViewModel,如果没有,则会创建
*/
inline fun <reified VM : ViewModel> Fragment.getAppViewModel(): VM {
(this.requireActivity().application as? RaiseSalaryApplication).let {
if (it == null) {
throw NullPointerException("未注册Application,无法使用getAppViewModel方法")
} else {
return it.getApplicationViewModel()[VM::class.java]
}
}
}
/**
* 在Fragment中获取与Activity同步的ViewModel
*/
inline fun <reified VM : ViewModel> Fragment.getActivityViewModel(): VM {
return ViewModelProvider(
requireActivity(),
ViewModelProvider.AndroidViewModelFactory(this.requireActivity().application)
)[VM::class.java]
}
这样就可以在Activity,或者Fragment中直接生成一个ViewModel在Application持有的ViewModel,可全局被监听,而不会主动销毁
在Activity中获取一个创建好的AppViewMdoel
private val appViewModel : AppViewModel by lazy { getAppViewModel<AppViewModel>() }
在Fragment中获取AppViewMdoel,并通过Activity来改变Value的值(这里主要是模拟在不同页面操作,也可以是在ActivityA中设置值,然后再ActivityB中监听,但是LiveData下发有个前提,页面必须活跃,所以只有在页面重新回到活动状态时,才会去拿到最新的值)
private val appViewModel: AppViewModel by lazy { getAppViewModel() }
fun setAppNameChange(){
appViewModel.appName.postValue("App Name = ${++valueCount}" )
}
...... 这里通过ViewBinding,给一个点击事件去Activity中改变值
collaborateBinding.tvSetAppName.setOnClickListener {
if (activity is ViewModelCollaborateActivity) {
(activity as ViewModelCollaborateActivity).setAppNameChange()
}
}
appViewModel.appName.observe(viewLifecycleOwner) {
//这就可以监听到值的改变
collaborateBinding.tvViewModelText.text = it
}
到这里一个全局的ViewModel创建与获取改变数据这一系列修改监听流程就结束了