Android Mvvm设计模式的详解与实战教程

一、介绍

        在开发设计模式中,模式经历了多次迭代,从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.genericSuperclassif (type != null && type is ParameterizedType) {val actualTypeArguments = type.actualTypeArgumentsval 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//配置当前页面布局资源@LayoutRespublic abstract fun getLayoutResId(): Intoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = DataBindingUtil.setContentView<T>(this, getLayoutResId())initViewModel()initObser()initDataBeforInitView()initVie()initDataAfterInitView()}//初始化viewmodelopen 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: Voverride fun initViewModel() {super.initViewModel()val type = javaClass.genericSuperclassif (type != null && type is ParameterizedType) {val actualTypeArguments = type.actualTypeArgumentsval 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.mzph.cn/news/54281.shtml

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

相关文章

三方接口调用设计方案

在为第三方系统提供接口的时候&#xff0c;肯定要考虑接口数据的安全问题&#xff0c;比如数据是否被篡改&#xff0c;数据是否已经过时&#xff0c;数据是否可以重复提交等问题 在设计三方接口调用的方案时&#xff0c;需要考虑到安全性和可用性。以下是一种设计方案的概述&a…

C# 学习笔记--个人学习使用 <2>

C# 学习笔记 Chapter 2 比较硬的基础部分Section 1 委托Part 1 Action 与 func 委托的示例Part 2 自定义委托Part 3 委托的一般使用Part 4 委托的高级使用Part 5 适时地使用接口 Interface 取代一些对委托的使用 Section 2 事件Part 1 初步了解事件Part 2 事件的应用Part 3 事件…

【Luniux】解决Ubuntu外接显示器不显示的问题

Luniux】解决Ubuntu外接显示器不显示的问题 文章目录 Luniux】解决Ubuntu外接显示器不显示的问题1. 检查nvidia显卡驱动是否正常2. 更新驱动3. 检查显示器是否能检测到Reference 1. 检查nvidia显卡驱动是否正常 使用命令行 nvidia-smi来检查显卡驱动是否正常&#xff0c;如果…

持续集成与持续交付:现代软件测试的变革之路

引言 在数字化时代&#xff0c;软件开发的速度和复杂性都在不断增加。为了满足市场的需求&#xff0c;企业需要更快、更高效地交付高质量的软件产品。在这样的背景下&#xff0c;持续集成与持续交付&#xff08;CI/CD&#xff09;成为了软件开发和测试的核心实践。 软件开发的…

论文阅读 The Power of Tiling for Small Object Detection

The Power of Tiling for Small Object Detection Abstract 基于深度神经网络的技术在目标检测和分类方面表现出色。但这些网络在适应移动平台时可能会降低准确性&#xff0c;因为图像分辨率的增加使问题变得更加困难。在低功耗移动设备上实现实时小物体检测一直是监控应用的…

小研究 - Java虚拟机性能及关键技术分析

利用specJVM98和Java Grande Forum Benchmark suite Benchmark集合对SJVM、IntelORP,Kaffe3种Java虚拟机进行系统测试。在对测试结果进行系统分析的基础上&#xff0c;比较了不同JVM实现对性能的影响和JVM中关键模块对JVM性能的影响&#xff0c;并提出了提高JVM性能的一些展望。…

css之文字连续光影特效、动画、scss

文章目录 效果图htmlscsscss 效果图 html <div><span>C</span><span>O</span><span>L</span><span>O</span><span>R</span><span>F</span><span>U</span><span>L</span&…

WOFOST模型与PCSE模型应用

实现作物产量的准确估算对于农田生态系统响应全球变化、可持续发展、科学粮食政策制定、粮食安全维护都至关重要。传统的经验模型、光能利用率模型等估产模型原理简单&#xff0c;数据容易获取&#xff0c;但是作物生长发育非常复杂&#xff0c;中间涉及众多生理生化过程&#…

Java学数据结构(2)——树Tree 二叉树binary tree 二叉查找树 AVL树 树的遍历

目录 引出什么是树Tree&#xff1f;树的实现二叉树binary tree查找树ADT——二叉查找树Binary Search Tree1.contains方法2.findMax和findMin方法3.insert方法4.remove方法&#xff08;复杂&#xff09;二叉查找树的深度 AVL(Adelson-Velskii和Landis)树——平衡条件(balance c…

流处理详解

【今日】 目录 一 Stream接口简介 Optional类 Collectors类 二 数据过滤 1. filter()方法 2.distinct()方法 3.limit()方法 4.skip()方法 三 数据映射 四 数据查找 1. allMatch()方法 2. anyMatch()方法 3. noneMatch()方法 4. findFirst()方法 五 数据收集…

Day43|leetcode 1049.最后一块石头的重量II、494.目标和、474.一和零

leetcode 1049.最后一块石头的重量II 题目链接&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;动态规划之背包问题&#xff0c;这个背包最多能装多少&#xff1f;LeetCode&#xff1a;1049.最后一块石头的重量II_哔哩…

date_range()函数--Pandas

1. 函数功能 生成连续的日期时间序列 2. 函数语法 pandas.date_range(startNone, endNone, periodsNone, freqNone, tzNone, normalizeFalse, nameNone, inclusiveboth, *, unitNone, **kwargs)3. 函数参数 参数含义start可选参数&#xff0c;起始日期end可选参数&#xff…

01-Flask-简介及环境准备

Flask-简介及环境准备 前言简介特点Flask 与 Django 的比较环境准备 前言 本篇来介绍下Python的web框架–Flask。 简介 Flask 是一个轻量级的 Web 框架&#xff0c;使用 Python 语言编写&#xff0c;较其他同类型框架更为灵活、轻便且容易上手&#xff0c;小型团队在短时间内…

QtCreator指定Windows Kits版本

先说下事件起因&#xff1a;之前一直在用Qt5.12.6&#xff0b;vs2017在写程序&#xff0c;后面调研了一个开源库Qaterial&#xff0c;但是翻来覆去的编译都有问题&#xff0c;后面升级到了Qt5.15.2&#xff0b;vs2019来进行cmake的编译&#xff0c;搞定了Qaterial&#xff0c;但…

软考A计划-系统集成项目管理工程师-小抄手册(共25章节)-下

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

深度学习经典检测方法的概述

深度学习经典的检测方法 two-stage&#xff08;两阶段&#xff09;&#xff1a;Faster-rcnn Mask-Rcnn系列 两阶段&#xff08;two-stage&#xff09;是指先通过一个区域提取网络&#xff08;region proposal network&#xff0c;RPN&#xff09;生成候选框&#xff0c;再通过…

SLAM十四讲学习笔记 第二期:部分课后实践代码

持续更新.... 前期准备第二讲实验一&#xff1a;简单输出 第五讲任务一&#xff1a;imageBasics&#xff08;Ubuntu配置opencv&#xff09;任务二&#xff1a;双目匹配点云&#xff08;Ubuntu配置pangolin&#xff09;检验部分我认为可以加深对CMake的理解 任务三&#xff1a;r…

pandas数据分析——groupby得到分组后的数据

groupbyagg分组聚合对数据字段进行合并拼接 Pandas怎样实现groupby聚合后字符串列的合并&#xff08;四十&#xff09; groupby得到分组后的数据 pandas—groupby如何得到分组里的数据 date_range补齐缺失日期 在处理时间序列的数据中&#xff0c;有时候会遇到有些日期的数…

springboot源码编译问题

问题一 Could not find artifact org.springframework.boot:spring-boot-starter-parent:pom:2.2.5.RELEASE in nexus-aliyun (http://maven.aliyun.com/nexus/content/groups/public/) 意思是无法在阿里云的镜像仓库中找到资源 解决&#xff1a;将配置的镜像删除即可&#…