升职加薪学习旅程 -- 设置全局可监听的ViewModel

首先一个全局的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创建与获取改变数据这一系列修改监听流程就结束了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容