Android Mvvm设计模式的详解与实现

news2025/1/16 7:54:54

一、介绍

        在开发设计模式中,模式经历了多次迭代,从MVC到MVP,再到如今的MVVM。发现的过程其实很简单,就是为了项目更好的管理。

        设计模式严格来说属于软件工程的范畴,但是如今在各大面试中或者开发中,设计模式被问的很多。特别是八股文的二十三种设计模式,可分三大类:行为型、结构型、创建型。

二、模式介绍

        模式的设计更多的体现在管理与架构能力,即使在项目中,你不用任何设计模式,代码也可以正常的跑起来,但是通过模式设计以后,在项目管理与质量控制,以及解耦等场景特别方便。

        任何设计模式和手段都是为了项目的更好管理,这种模式更像一种流程。从技术角度来分析,不能作为衡量一个人的技术好坏,但是可以作为参考,来判断一个人的综合能力以及设计、架构能力。

了解设计模式,可以提高一个人的综合能力。

三、MVMM详解与设计

MVVM是什么

        目前在做有UI展示的一些项目或者端,都在说MVVM设计模式。MVVM全程view-viewModel-Model。还是分为三层,View层,viewModel:view与业务层,Model数据业务层

View:是我们fragment或者Activity界面,主要处理UI渲染和交互的

viewModel:介于view与Module之前,处理数据与逻辑上的,将Model请求的结果返回给view层

Model:与viewModel打交道,将view需要的数据通过Model层来请求,然后将请求到的结果返回给viewModel。

Mvvm流程

        在Mvvm设计模式中,view主要就是做数据与UI的绑定,常见的View与Model没有直接交互,需要申明都是通过ViewModel进行交互的。ViewModel从名字就可以看出,是View与Model的拼写,所以肯定是与View和Moel有关,在MVVM中,ViewModel的核心作用就是作为View与Model的桥梁,将View的需求告诉Model,然后从Model中将结果拿到,处理好给View,View进行渲染。

Mvvm的助手databinding:

        通过Google官方我们也了解到,MVVM的推波导致了DataBinding的被很好的推广,在Mvvm中,View中的绑定和页面的view是通过Databinding来完成,很多开发者可能还没体验过DataBinding,甚至也没有使用过,这个也不影响到Mvvm的使用,因为DataBinding只负责View与Data的绑定,即使你不会可以手动处理。

如果想了解DataBinding的小伙伴,可以看博主一下的文档:

Android databinding的接入使用与详解(一)_android databinding使用_蜗牛、Z的博客-CSDN博客

Android databinding之RecycleView使用与讲解(二)_android databinding recyclerview_蜗牛、Z的博客-CSDN博客

Android databinding之数据单向与双向绑定详解与使用(三)_databinding双向绑定_蜗牛、Z的博客-CSDN博客

Android databinding之BindingAdapter与BindingConversion详解与使用(四)_蜗牛、Z的博客-CSDN博客

Android databinding之BindingMethod与BindingMethods介绍与使用(五)_android开发bindingmethods的使用_蜗牛、Z的博客-CSDN博客

Android DataBinding之布局include 和 viewStub详解与使用(六)_databinding viewstub_蜗牛、Z的博客-CSDN博客

Android DataBinding之布局中(layout)事件、运算逻辑、资源、工具类的使用与详解(七)_databinding layout_蜗牛、Z的博客-CSDN博客

新手礼包:

        这几篇文档基本都是从零开始学databinding的文章,只要你跟着看,慢慢实践里面的dmeo,都是没问题的。以上新手礼包可以帮你很好的处理Mvvm中数据的绑定

数据传递MutableLiveData:

通过以上知道ViewModel与View进行数据交互,他们之间如何传递数据?在viewmodel中提供了

MutableLiveData,它继承了LiveData,类似事件订阅,你发送了数据,在view中订阅即可,数据将会回传到订阅处。LiveData也支持生命周期的绑定,防止数据订阅中,当前页面销毁,数据还在订阅,导致页面发生内存泄露。

四、实战

        通过以上的学习,我们大概了解了Mvvm包括哪些?如何架构和搭建MVVM。通过关键模块的处理我们将继续学习实战。

依赖库:

    implementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0"
    implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"

Model模块

model主要是数据处理,在搭建代码的时候,我们最好有良好的编程风格,可以先搭建一个基础、抽象类,后面的model都继承直接使用,即使是空类也要写一个,方便以后扩展。

open abstract class BaseModel {
}
//一般梳理数据类比较多
class MyModel : BaseModel() {

    //网络数据的获取


    //数据库的操作


    //本地的数据缓存:添加与删除

    public fun getInitData():String{
        return "init data that info"
    }


}

Model的是和数据打交道,处理好,我们就可以处理搭建ViewModel了

ViewModel层:

ViewModel层夹在View与model之间,是逻辑的中转,view要什么找ViewModel,model通过ViewModel把数据传递给View。

ViewModel这里面主要有两块:搭建和创建

搭建

搭建需要继承public AndroidViewModel(@NonNull Application application),由于ViewModel需要与View合作,所以还需要了解当前的对象生命周期防止内存泄露等发生。

这里需要使用到接口:LifecycleObserver

LifecycleObserver用法:

直接继承,然后通过状态绑定对应的方法,当lifecycle绑定完就可以分发生命周期状态

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public fun onstart(){
        log("onstart")
    }
1、生命状态回调

//定义了页面监听生命周期监听
interface BaseViewModelLifecycleObserver : LifecycleObserver {

    companion object{
        const val TAG="life"
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public fun onstart(){
        log("onstart")
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public fun onStop() {
        log("onStop")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public fun onResume() {
        log("onResume")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public fun onPause() {
        log("onPause")
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public fun ondestory() {

        log("ondestory")
    }


    public fun log(msg:String)
    {
        Log.e(TAG,"${msg}")
    }
}
2、BaseViewModel
abstract open class BaseViewModel(val context: Application) : AndroidViewModel(context),
    BaseViewModelLifecycleObserver {

}
3、定义业务的ViewModel
class MyViewModel(context: Application) : BaseViewModel(context) {


    private val model: MyModel by lazy { MyModel() }

    public val initLiveData: MutableLiveData<String> by lazy { MutableLiveData() }


    public fun showToast(msg: String) {
        Toast.makeText(getApplication(), msg, Toast.LENGTH_SHORT).show()

    }

    public fun initData() {
        val data=model.getInitData()
        initLiveData.value=data
    }


}

这里面多了一个MutableLiveData,就是数据回传的订阅,ViewModel发送了数据给View通过LiveData进行订阅。在这里面要创建Model对象

创建

创建这里面涉及到了kotlin的泛型问题,相比Java,kotlin的泛型比较复杂,由于创建是和DataBinding绑在一起的,这边先介绍泛型的创建与生命周期的绑定

    val type = javaClass.genericSuperclass
        if (type != null && type is ParameterizedType) {
            val actualTypeArguments = type.actualTypeArguments
            val tClass = actualTypeArguments[1]
viewModel= AndroidViewModelFactory.getInstance(application).create(tClass as Class<V>)
        }


        lifecycle.addObserver(viewModel)

    lifecycle.addObserver(viewModel):绑定了当前的生命周期

注意:在需要消费,否则导致内存泄露

    override fun onDestroy() {
        super.onDestroy()
        lifecycle.removeObserver(viewModel)
    }

View模块

View模块主要就是DataBinding的创建与ViewMOdel的创建,ViewModel上面已介绍如何创建,下面将介绍如何去架构这个基础页面,去管理

这边架构的页面分为两个类:第一个是DataBinding类,还有一个是DataBinding与ViewModel继承类,为什么要分开?因为在正常业务中,有些模块不需要ViewModel,但是DataBinding是必须使用,所以只需要继承DataBinding类即可。

DataBinding基础类:
 

open abstract class BaseDataBindModelActivity<T : ViewDataBinding>() : FragmentActivity() {

    public lateinit var binding: T

    //配置当前页面布局资源
    @LayoutRes
    public abstract fun getLayoutResId(): Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView<T>(this, getLayoutResId())
        initViewModel()
        initObser()
        initDataBeforInitView()
        initVie()
        initDataAfterInitView()

    }


    //初始化viewmodel
    open protected fun initViewModel() {

    }

    //初始化页面
    abstract fun initVie()


    //初始化livedata的监听,
    abstract fun initObser()

    //获取数据在initview之前
    abstract fun initDataBeforInitView()

    //获取数据在initview之后
    abstract fun initDataAfterInitView()


    //页面消费之前,解绑
    override fun onDestroy() {
        if (binding != null) {
            binding.unbind()
        }
        super.onDestroy()
    }


}

ViewModelDataBinding基础类:

abstract class BaseViewModelBindActivity<T : ViewDataBinding, V : BaseViewModel>() :
    BaseDataBindModelActivity<T>() {

    lateinit var viewModel: V

    override fun initViewModel() {
        super.initViewModel()
        val type = javaClass.genericSuperclass
        if (type != null && type is ParameterizedType) {
            val actualTypeArguments = type.actualTypeArguments
            val tClass = actualTypeArguments[1]

            viewModel= AndroidViewModelFactory.getInstance(application).create(tClass as Class<V>)
        }


        lifecycle.addObserver(viewModel)
    }


    override fun onDestroy() {
        super.onDestroy()
        lifecycle.removeObserver(viewModel)
    }




}

通过以上的配置,基本已完成了MVVM的搭建。

小时牛刀:

class MyTestViewBindActivity : BaseViewModelBindActivity<TestViewBind, MyViewModel>() {

    override fun getLayoutResId(): Int {
        return R.layout.layout_test_view_bind
    }

    override fun initVie() {
        binding.btnTest.setOnClickListener {
            viewModel.showToast("你好")
        }

        binding.btnInit.setOnClickListener {

            //调用了初始化事件
            viewModel.initData()
        }
    }

    override fun initObser() {

        //数据订阅事件
        viewModel.initLiveData.observe(this) {
            binding.textInfo.text = it
        }


    }

    override fun initDataBeforInitView() {

    }

    override fun initDataAfterInitView() {

    }
}

绑定的页面生命周期回调:

运行效果

五、总结

1.通过以上学习,完成了MVVM的基础结构与如何架构一个MVVM页面出来。Demo中也基本完成了大家的难点问题。

2.如果不了解生命周期的可以参考Demo中直接拿去用,避免处理不好导致内存泄露

3.MVVM需要databinding的参与,如果不了解的小伙伴直接看我的DataBinding文章,看完直接上项目使用是没任何问题,有问题我得文章中也会提出,这边都是干货,都是博主自己总结与写出来的。希望大家能够受益。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/944454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 更新语句是怎么执行的

更新语句的执行流程 更新语句的执行流程图为什么要两阶段提交呢&#xff1f; 更新语句的执行流程图 更新语句的执行是 Server 层和引擎层配合完成&#xff0c;数据除了要写入表中&#xff0c;还要记录相应的日志。 update 语句的执行流程图&#xff0c;图中浅色框表示是在 In…

为何反射探针关闭Mipmap后变成了白图

1&#xff09;为何反射探针关闭Mipmap后变成了白图 2&#xff09;2021.3 Android从AssetBundle中加载视频播放失败问题 3&#xff09;SBP是否可以解决打包时FBX等模型文件中额外的GameObject 4&#xff09;Addressables加载已打包过的Prefab后Mono脚本丢失 这是第349篇UWA技术知…

CSS3D+动画

CSS3D 1.css3D 给父元素设置 perspective:景深:近大远小的效果900-1200px这个范围内 transform-style:是否设置3D环境 flat 2D环境 默认值 perserve-3D环境 3D功能函数 1.位移: translateZ()translate3D(x,y,z) <!DOCTYPE html> <html lang"en"><h…

【Python小练习】利用DES进行加密解密

from Crypto.Cipher import DES from Crypto.Util.Padding import pad, unpad import json# 创建 DES 加密对象 key b123456 # 8字节的密钥&#xff0c;注意必须为字节类型 cipher DES.new(key, DES.MODE_ECB)# 加密 def encrypt_data(data):plaintext json.dumps(data).en…

安防视频监控/视频集中存储/云存储平台EasyCVR平台无法播放HLS协议该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

【Java基础篇】一文搞懂Java方法的调用与重载(超详细)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 目录 一、方法的概念以及使用1.1什么是方法1.2方法定义1.3方法调用的执行过程1.4形参和实参的关系 二、方法的重载方…

MT4中如何设置Heikin-Ashi图表,10秒钟教会

所有人都在告诉你&#xff0c;在MT4中使用Heikin-Ashi烛台图表能在交易中盈利&#xff0c;但没有人告诉如何在MT4中添加Heikin-Ashi图表&#xff0c;如何设置Heikin-Ashi图表&#xff0c;其实很简单&#xff0c;FPmarkets澳福10秒钟教会&#xff0c;如果不好使&#xff0c;FPma…

VS2008统计代码行数

1.利用组合键&#xff08;ctrl shift F&#xff09;&#xff0c;查找&#xff1a; b*[^:b#/].*$ 结果如下&#xff1a; 如图所示&#xff0c;一共 104093行代码。

【网络安全防护】上海道宁与Bitdefender帮助您构建弹性网络并降低安全运营成本

在网络的世界中 风险变得更加常见与复杂 企业需要从网络安全转向网络弹性 复杂的网络攻击已非常普遍 在面临攻击时 企业如何保持业务连续性&#xff1f; Bitdefender GravityZone将 风险分析、安全加固、威胁预防 检测和响应功能相结合 帮助您构建弹性网络 并降低安全…

vue集成mars3d后,basemaps加不上去

首先&#xff1a; <template> <div id"centerDiv" class"mapcontainer"> <mars-map :url"configUrl" οnlοad"onMapload" /> </div> </template> <script> import MarsMap from ../component…

如何利用 CRM 做好销售渠道管理?

销售渠道管理是成功销售战略的一个重要方面。它涉及建立、跟踪和组织销售流程的各个阶段&#xff0c;以确保顺利、高效地将潜在客户转化为付费客户。 销售渠道管理为跟踪和优先处理交易提供了一个清晰的框架&#xff0c;采用销售渠道漏斗模板可以进一步简化流程。通过有效管理…

Linux系统下vim常用命令

一、基础命令&#xff1a; v:可视模式 i:插入模式 esc:命令模式下 :q &#xff1a;退出 :wq &#xff1a;保存并退出 ZZ&#xff1a;保存并退出 :q! &#xff1a;不保存并强制退出二、在Esc下&#xff1a; dd : 删除当前行 yy:复制当前行 p:复制已粘贴的文本 u:撤销上一步 U:…

使用Python和systemctl管理Linux系统服务的简便工具

前言 本文介绍了一个实用工具&#xff0c;用于在Linux系统上管理systemctl服务。该工具提供了创建、安装、卸载、启动和停止服务的功能&#xff0c;帮助用户轻松地管理和控制正在运行的服务。 通过使用该代码&#xff0c;你可以轻松地执行以下操作&#xff1a; 创建服务文件&…

解决centos离线安装cmake找不到OpenSSL问题

安装方法&#xff1a;见另外一篇文章 https://blog.csdn.net/zhongxj183/article/details/118488629 按照文章下载了离线gcc 和OpenSSL&#xff0c;以及在cmake官网下载了最新版 cmake-3.27.4.tar.gz 顺利安装gcc 和OpenSSL 但执行编译cmake时&#xff0c;报错找不到OpenSSL…

软考A计划-网络工程师-必考知识点-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

液冷连接器快速接头

液冷连接器快速接头常用介质 水、乙二醇水溶液、纯乙二醇、空调制冷剂和硅油等。 液冷连接器快速接头应用 强振动冷却回路手动连接雷达数据中心电子冷却吊舱 液冷连接器快速接头材质 主体材料不锈钢或经表面处理的铝合金 密封圈选用低温硅橡胶或HNBR 液冷连接器快速接头主…

5G智能网关如何解决城市停车痛点难点

2023年上半年&#xff0c;我国汽车新注册登记1175万辆&#xff0c;同比增长5.8%&#xff0c;88个城市汽车保有量超过100万辆&#xff0c;北京、成都等24个城市超过300万辆。随着车辆保有量持续增加&#xff0c;停车难问题长期困扰城市居民&#xff0c;也导致城市路段违停普遍、…

架构设计:Docker容器化部署

在现代软件开发和部署中&#xff0c;Docker 容器化技术已经成为一种重要的解决方案。它不仅简化了应用程序的构建和部署过程&#xff0c;还提供了跨环境一致性、可移植性和高效性。本文将介绍一个完整的 Docker 容器化部署架构设计&#xff0c;帮助您深入了解如何将应用程序成功…

mysql中的with

概念 WITH 子句是 MySQL 中的一种 SQL 结构&#xff0c;又称为 Common Table Expression (CTE)。它在不影响原有 SQL 语句的情况下&#xff0c;允许开发人员临时创建一个内存中的结果集&#xff0c;然后对其进行操作。 作用 WITH 子句的主要用途是创建一个暂时的结果集&…

NewStarCTF 2022 web方向题解 wp

----------WEEK1---------- BUU NewStarCTF 公开赛赛道 WEEK1 [NotPHP] 先看题目&#xff0c;要传参加绕过。 分析一下代码&#xff1a;首先get一个datadata://test/plain,Wel…。然后key1和2用数组可以绕过。num2077a可以绕过弱类型。eval()中的php语句被#注释了&#xff0c…