Mvvm探究集成与使用

作者 : 开心源码 本文共3745个字,预计阅读时间需要10分钟 发布时间: 2022-05-12 共167人阅读

Mvvm探究集成与使用

前言

Android开发中常常会有activity中数据操作过多导致代码臃肿且杂乱的问题,完全不符合面向对象编程的”责任单一性”准则,通常会有很多种处理方案,MVP,MVVM等(android本身的模式可以看做一种MVC)
Google官方17年开始提供了一系列开发框架帮助开发者专注于业务,快速开发android程序,其中对于处理这个问题就有ViewModelLiveData两种(实际上还有处理生命周期导致的泄漏问题,工作在后端的Lifecycles )

ViewModel 将视图的数据和逻辑从具备生命周期特性的实体(如 Activity 和 Fragment)中剥离开来。直到关联的 Activity 或者 Fragment 完全销毁时,ViewModel 才会随之消失,也就是说,即便在旋转屏幕导致 Fragment 被重新创立等事件中,视图数据仍旧会被保留。ViewModels 不仅消除了常见的生命周期问题,而且可以帮助构建更为板块化、更方便测试的客户界面。

ViewModel的优点很显著,为Activity 、Fragment存储数据,直到完全销毁。尤其是屏幕旋转的场景,常用的方法都是通过onSaveInstanceState()保存数据,再在onCreate()中恢复,真的是很麻烦。由于ViewModel存储了数据,所以ViewModel可以在当前Activity的Fragment中实现数据共享。

LiveData 是一个可以感知 Activity 、Fragment生命周期的数据容器。当 LiveData 所持有的数据改变时,它会通知相应的界面代码进行升级。同时,LiveData 持有界面代码 Lifecycle 的引用,这意味着它会在界面代码(LifecycleOwner)的生命周期处于 started 或者 resumed 时作出相应升级,而在 LifecycleOwner 被销毁时中止升级。

LiveData的优点:不用手动控制生命周期,不用担心内存泄露,数据变化时会收到通知。
那么LiveDataViewModel的组合使用可以说是双剑合璧,而Lifecycles贯穿其中。

以上是相关基础知识点,本文着重详情集成方式与使用集成后的代码,不详情上面三者详细使用,下图是集成后相关的UML图

无标题.png

准备

导入

主要要导入google的LiveData,LifecyclesViewModel

implementation 'androidx.appcompat:appcompat:1.0.2'implementation "android.arch.lifecycle:extensions:1.1.1"

配置

已经集成到框架雏形
https://git.dev.tencent.com/zhoulei26/android-scarlet.git

代码解释

ViewModel的获取和activity相关
在Activity的基类中加入

    /**     * 获取自己设置的VM得方法     */    inline fun <reified T : MyLiveModel<T>> initMyLiveModel(init: T): T {        return ViewModelProviders.of(this).get(T::class.java).apply {            mutableLiveData.postValue(init)        }    }    /**     * 简单的ViewModel     */    inline fun <reified T> simpleVm(init: T): MyLiveModel<T> {        return ViewModelProviders.of(this).get(SimpleVm<T>().javaClass).apply {            mutableLiveData.postValue(init)        }    }

在Fragment的基类中,此处的上下文填的是activity

       /**     * 获取自己设置的VM得方法     */    inline fun <reified T : MyLiveModel<T>> initMyLiveModel(init: T): T {        return ViewModelProviders.of(activity!!).get(T::class.java).apply {            mutableLiveData.postValue(init)        }    }    /**     * 简单的ViewModel     */    inline fun <reified T> simpleVm(init: T): MyLiveModel<T> {        return ViewModelProviders.of(activity!!).get(SimpleVm<T>().javaClass).apply {            mutableLiveData.postValue(init)        }    }

common目录下新建文件mvvm.kt

interface Mvvm {    val vm: MyLiveModel<*>}abstract class MyLiveModel<T> : ViewModel() {    val mutableLiveData = MutableLiveData<T>()    /**     * 使用edit将自动发送数据到订阅的地方,否则应该手动调用notifyDataSetChang(),任何地方可以调用     */    fun notifyDataSetChang() {        if (mutableLiveData.value == null)            throw RuntimeException("MutableLiveData Null!!!")        else {            mutableLiveData.postValue(this as T)        }    }    /**     * 修改MutableLiveData中的值并且发送数据,订阅者将升级,任何地方可以调用     */    fun edit(block: T.() -> Unit) {        if (mutableLiveData.value == null)            throw RuntimeException("MutableLiveData Null!!!")        else {            val cur: T = mutableLiveData.value!!            cur.block()            mutableLiveData.postValue(cur)        }    }    /**     * 将vm的数据和view进行绑定     * 在[block]中设置view     */    fun subscribe(@NonNull owner: LifecycleOwner, block: (T) -> Unit) {        mutableLiveData.observe(owner, Observer {            block(it as T)        })    }}class SimpleVm<T> : MyLiveModel<T>()

配置完成

开始使用

1.定义model

data class User(    var name: String = "123",    var age: Int = 1,    var count: Int = 0)

2.在Activity和Fragment中…

  • Activity
class ViewModelActivity : BaseActivity(), Mvvm {            override val vm by lazy { simpleVm(User()) }            ... }
  • Fragment
class Blank1Fragment : BaseFragment(),Mvvm {   override val vm by lazy { simpleVm(User()) }...}
  • 订阅数据
//activity和fragment操作相同  vm.subscribe(this){            tx1.text="我是fragment1 年龄${it.age}"        }
  • 升级数据
//任何地方vm.edit {  age++}//或者者修改数据之后vm.notifyDataSetChang()

3.自己设置用法

上面是最简单的情况,viewModle应该是解耦界面和数据的利器,即应该包含各种复杂的数据操作
自己设置一个

fun User.crazy() {    name = "我TM疯了"    age = 111}class Fuza : MyLiveModel<Fuza>() {    var count: Int = 0    var user = User()        //使用edit将自动发送数据到订阅的地方,否则应该手动调用notifyDataSetChang()    fun add(i: Int) {        edit {            user.age *= i            count += i        }    }    //可以放网络操作或者者数据库操作等等    fun updataUser() {        user.crazy()        notifyDataSetChang()    }}//自己设置的vm获取方式,在上下文中 override val vm by lazy { initMyLiveModel(Fuza()) }//在界面可以触发,比方bt.click{    vm.updataUser()}

5.其余

整个封装旨在使用更简单,更容易专注于业务,若需要更复杂的用法还需要自行学习Google的相关库

结语

使用mvvm之后使得界面和数据完全解耦
实际上完全的,更进一步的解耦,vm和界面应该由接口沟通,即界面只管使用vm的接口,而无需管vm的实现,考虑到我们的开发团队与程序规模,我没有加入相关的内容
相关demo git库
https://git.dev.tencent.com/zhoulei26/android-scarlet.git

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Mvvm探究集成与使用

发表回复