Android MVVM架构

article/2025/9/30 8:31:43

1.MVC,MVP,MVVVM

1.1什么是MVVM

1.MVVM,是Model-View-ViewModel的简写,是M-V-VM三部分组成。它本质上就是MVC 的改进 版。MVVM 就是将其中的View 的状态和行为抽象化,其中ViewModel将视图 UI 和业务逻辑分 开,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。

2.MVVM采用双向数据绑定,view中数据变化将自动反映到viewmodel上,反之,model中数据变化 也将会自动展示在页面上。把Model和View关联起来的就是ViewModel。ViewModel负责把Model 的数据同步到View显示出来,还负责把View的修改同步回Model。

3.MVVM核心思想,是关注model的变化,让MVVM框架利用自己的机制自动更新DOM,也就是所 谓的数据-视图分离,数据不会影响视图。

如图(重点):

 

 1.2 Android MVVM

MVVM分为Model,View,ViewModel 三个部分

Model:数据层,包含数据实体和对数据实体的操作,和MVP的model没有区别。

View: 界面层,对应于Activity,XML,负责数据显示以及用户交互。相比MVP的view,这里面的 view视图数据一般是在xml中使用DataBinding进来双向绑定数据的。    

ViewModel:关联层,作为中间桥梁 去通知model数据层处理数据业务,并将结果回调给 UI 层处 理 UI 逻辑。ViewModel中只有activity持有vm引用,vm是不持有view的引用的,所以vm的构造方 法中不能传入视图相关的对象。所以重点在于怎么通知view,可以通过观察者回调的方式。但是现 在一般是结合Jetpack来进行view的更新的。

2.MVVM项目框架

如图:

 3 MVVM核心构成

3.1 DataBinding (重点)(详细讲解)

数据和UI双向绑定

3.2 LifeCycle

界面生命周期感知

3.3 ViewModel

业务逻辑

3.4 LiveData

可观察数据项

3.5 MVVM项目框架搭建 通用性的快速开发框架 可应用各项目中

4 DataBinding

4.1 DataBinding的简介

1.Data binding 在2015年7月发布的android Studio v1.3.0 版本上引入,在2016年4月Android Studio v2.0.0 上正式支持。目前为止,Data Binding 已经支持双向绑定了,实在2016年的google I/O大会上发布的。现在已经很普及啦,在项目中也在慢慢使用。

 2.I/O大会上发布的。现在已经很普及啦,在项目中也在慢慢使用。 Databinding 是一个实现数据和UI绑定的框架,是一个实现 MVVM 模式的工具,有了 Data Binding,在Android中也可以很方便的实现MVVM开发模式。会java web开发的会更好的理解在 xml中绑定数据的模式,在web开发中也是使用@{}来实现数据的显示的。

3.Data Binding 是一个support库,最低支持到Android 2.1(API Level 7+)。使用 DataBing,Gradle的Android Plugin需要在1.5.0-alpha1以上。

4.Data Binding 之前我们不可避免地要编写大量的毫无营养的代码,如 findViewById()、 setText(),setVisibility(),setEnabled() 或 setOnClickListener() 等,通过 Data Binding , 我们可 以通过声明式布局以精简的代码来绑定应用程序逻辑和布局,这样就不用编写大量的毫无营养的代 码了。

缺点:

1. ViewModel与View一一对应;

2. 使用起来灵活性比较低;

3. Model属性发生变化时,ViewDatabinding采用异步更新数据,对于现实大量数据的ListView,会 有一定延迟,在实践测试中发现,Databing效率较低,对于负责的界面不太适用;

4. 自动生成大量代码和属性字段:ViewDataBinding 实现类 DataBinderMapper 等。

4.2使用DataBinding

具体步骤:

1.构建环境(Build Environment)

在build.gradle中添加如下代码:

 

dataBinding {enabled = true}

2. 数据绑定布局文件

数据绑定的布局文件和我们以前经常写的布局文件稍有不同,并从布局的根标记开始,后面依次是数据 元素和视图根元素,即根布局是 layout,接下来是 data 节点,variable 节点,示例如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="user"type="com.hp.mvvmdemo.model.User" /><variablename="handler"type="com.hp.mvvmdemo.view.activity.MainActivity.Handler" /></data><LinearLayoutandroid:gravity="center"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tv_show"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!" /><TextViewandroid:layout_marginTop="30dp"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20dp"android:text="@{user.username}" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20dp"android:text="@{user.password}" /><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="@{()->handler.onClick()}"/></LinearLayout></layout>

3.在MainActivity.java中获取bingding对象

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//setContentView(R.layout.activity_main);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);}

4.4databinding点击事件

xml:

 

 activity:

 5.单向绑定

5.1单个值的绑定:

1.集成DataDinding 添加 dataBinding.enabled true 和 dataBinding { enabled = true }

android {
....
dataBinding {
enabled = true
}
}

2.实现xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data><variablename="title"type="java.lang.String" />
</data>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:textColor="#000000"android:id="@+id/tvTitle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{title}"/>
</LinearLayout>
</layout>

5.2对象的绑定:

1.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data><variable name="user" type="com.example.User"/>
</data>
<LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.firstName}"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.lastName}"/>
</LinearLayout>
</layout>

2.实体类:

public class User {private final String firstName;private final String lastName;public User(String firstName, String lastName) {this.firstName = firstName;this.lastName = lastName;}public String getFirstName() {return this.firstName;}public String getLastName() {return this.lastName;}
}

3.databinding:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);MainActivityBinding binding = DataBindingUtil.setContentView(this,R.layout.main_activity);User user = new User("Test", "User");binding.setUser(user);}

6.双向绑定

双向绑定是指其中任意一个变化后都会同步更新到另一个。双向绑定使用@={}表达式来实现 4.5.1 目前已经支持双向绑定的列表

 7.从网页获取图片

整体架构:

 

导入要使用的依赖:

build.gradle        

implementation 'com.squareup.picasso:picasso:2.71828'//for rxjavaimplementation 'io.reactivex.rxjava2:rxjava:2.2.6'//for rxandroidimplementation 'io.reactivex.rxjava2:rxandroid:2.1.1'//衔接 Retrofit & RxJava,此处一定要注意使用RxJava2的版本implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'//添加Retrofit依赖implementation 'com.squareup.retrofit2:retrofit:2.5.0'//添加Gson解析implementation 'com.squareup.retrofit2:converter-gson:2.5.0'//添加图片加载库依赖implementation 'com.github.bumptech.glide:glide:4.12.0'

xml层:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="imgurl"type="String" /><variablename="localurl"type="int" /><variablename="mainviewmodel"type="com.hp.day48stage01.viewmodel.MainViewModel" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.activity.MainActivity"><ImageViewapp:netImage="@{imgurl}"app:localImage="@{localurl}"android:id="@+id/imageView"android:layout_width="300dp"android:layout_height="300dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:srcCompat="@drawable/ic_launcher_background" /><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="64dp"android:text="点击见美女"android:onClick="@{()->mainviewmodel.onChange()}"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="@+id/imageView"app:layout_constraintHorizontal_bias="0.495"app:layout_constraintStart_toStartOf="@+id/imageView"app:layout_constraintTop_toBottomOf="@+id/imageView"app:layout_constraintVertical_bias="0.029" /></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

编写实体类:

ModelGril.java

public class ModelGirl {private boolean success;private String imgurl;private Info info;@Overridepublic String toString() {return "MobileGirl{" +"success=" + success +", imgurl='" + imgurl + '\'' +", info=" + info +'}';}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}public String getImgurl() {return imgurl;}public void setImgurl(String imgurl) {this.imgurl = imgurl;}public Info getInfo() {return info;}public void setInfo(Info info) {this.info = info;}public static class Info{private int width;private int height;private String type;public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public String getType() {return type;}public void setType(String type) {this.type = type;}}}

编写网络接口:

public interface GetImage_Interface {@GET("api/mobil.girl?type=json")Observable<ModelGirl> getPic();
}

适配器:

public class ImageBindingAdapter {@BindingAdapter(value = {"netImage","localImage"},requireAll = false)public static void setImage(ImageView imageView,String url,int path){if (url != null && !"".equals(imageView)) {/*Glide.with(imageView.getContext()).load(url).override(300,300).centerCrop().into(imageView);*/Picasso.get().load(url).placeholder(R.mipmap.jiazai).into(imageView);}else {imageView.setImageResource(path);}}}
MainViewModel
public class MainViewModel {private String imgurl;private ModelGirl modelGirl;private ActivityMainBinding binding;private final String TAG = "MainViewModel";public ModelGirl getModelGirl() {return modelGirl;}public void setModelGirl(ModelGirl modelGirl) {this.modelGirl = modelGirl;}public MainViewModel() {}public MainViewModel(ActivityMainBinding binding,String imgurl) {this.binding = binding;this.imgurl = imgurl;initGirl();}private void initGirl() {Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.vvhan.com/").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();GetImage_Interface request = retrofit.create(GetImage_Interface.class);Observable<ModelGirl> observable = request.getPic();observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<ModelGirl>() {@Overridepublic void accept(ModelGirl modelGirl) throws Exception {Log.i(TAG,"连接成功");//Log.i(TAG, modelGirl.toString());imgurl = modelGirl.getImgurl();binding.setImgurl(imgurl);}}, new Consumer<Throwable>() {@Overridepublic void accept(Throwable throwable) throws Exception {Log.i(TAG,"连接失败");}});}public void onChange(){initGirl();}
}
MainActivity:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);binding.setMainviewmodel(new MainViewModel(binding,""));}
}


http://chatgpt.dhexx.cn/article/IfwxeaHt.shtml

相关文章

Maven(mvn)的学习下载和配置

文章目录 Maven&#xff08;mvn&#xff09;1.Maven 是什么&#xff1f;2.Maven做什么&#xff1f;2.1传统方式对项目的管理2.2Maven对jar包的管理 3.Maven怎么学3.1Maven如何创建项目3.2Maven的下载与配置3.3Maven的项目结构3.4Maven依赖的引入3.5Maven依赖的剔除3.6Maven依赖…

Android之 MVC到MVVM架构发展和封装

一 简介 1.1 软件架构发展趋势是解耦&#xff0c;即分离数据层和视图层&#xff0c;使得数据层专注于业务的数据和逻辑处理。从而提高代码的可读可编辑效率&#xff0c;提高团队协作能力&#xff0c;项目的生产能力&#xff0c;降低后期维护成本。 1.2 Android架构发展MVC -…

安卓mvvm

AndroidX的意思是android extension libraries, 也就是安卓扩展包 AndroidX其实是Jetpack类库的命名空间 (190条消息) AndroidX初识_Neda Wang的博客-CSDN博客https://blog.csdn.net/weixin_38261570/article/details/111500044 viewmodel Android 面试总结 - ViewModel - 知…

Android MVVM的实现

Android MVVM的实现 前言&#xff1a; 在我们写一些项目的时候&#xff0c;通常会对一些常用的一些常用功能进行抽象封装&#xff0c;简单例子&#xff1a;比如BaseActivity&#xff0c;BaseFragment等等…一般这些Base会去承载一些比如标题栏&#xff0c;主题之类的工作&…

Android MVI框架搭建与使用

MVI框架搭建与使用 前言正文一、创建项目① 配置AndroidManifest.xml② 配置app的build.gradle 二、网络请求① 生成数据类② 接口类③ 网络请求工具类 三、意图与状态① 创建意图② 创建状态 四、ViewModel① 创建存储库② 创建ViewModel③ 创建ViewModel工厂 五、UI① 列表适…

Android MVVN 使用入门

MVVM&#xff08;Model-View-ViewModel&#xff09;是一种基于数据绑定的设计模式&#xff0c;它与传统的 MVC 和 MVP 模式相比&#xff0c;更加适合处理复杂的 UI 逻辑和数据展示。在 Android 开发中&#xff0c;MVVM 通常使用 Data Binding 和 ViewModel 实现。 下面是一个简…

mvnw的使用

1、什么是mvnw mvnw是Maven Wrapper的缩写。我们安装Maven时&#xff0c;默认系统所有项目都会使用全局安装的这个Maven版本。但对于某些项目来说&#xff0c;它可能必须使用某个特定的Maven版本&#xff0c;这时就可以使用Maven Wrapper&#xff0c;它可以负责给这个特定的项…

快速查找参考文献影响因子——ScholarScope

前言&#xff1a; 最初看到的关于查看影响因子的插件有&#xff1a;pubmedy, pubmed plus 和 scholar scope. 试了pubmedy&#xff0c;找到的版本没有用。 PubMed 是一个提供生物医学方面的论文搜寻以及摘要&#xff0c;并且免费搜寻的数据库。它的数据库来源为MEDLINE。其核心…

新手刚学js遇到的ie6问题

2019独角兽企业重金招聘Python工程师标准>>> 1.前段时间遇到一个需求&#xff0c;需要让图片在点击tab的时候加载。如果那个tab是由a标签组成的&#xff0c;这时候你就需要在click之后return false。不然坑爹的ie6是没法显示图片的。 2.有个需求是&#xff0c;做一…

查看文章影响因子的插件_查询文献可实时显示影响因子与分区排名的2个强大浏览器插件...

首先,看下我们普通的PubMed文献查找页面,是下图这样子的: 可是装了两个国产神器之后,文献的检索结果列表是下图这样的,可以实时查看文章的影响因子、研究领域的排名,以及全文下载链接、引文格式等。 而这两个神器其实只是两款非常小的浏览器插件:PubMedy和Scholarscope。…

python 贪吃蛇游戏代码

第一步&#xff1a;蛇形 运行IDLE&#xff0c;打开一个新的文本编辑窗口。输入以下的代码&#xff1a; # -*- coding: UTF-8 -*- # 1 - 引入模块 import pygame from pygame.locals import * import sys,random,time,math# 2 - 初始化pygame pygame.init() fpsClock pygame.…

简单的贪吃蛇

最近都在忙着复习考试&#xff0c;忙里偷闲&#xff0c;抽出时间写了个贪吃蛇&#xff0c;没时间写详细的思路了&#xff0c;代码里有比较详细的注释&#xff0c;有兴趣的同学可以自己看看。&#xff08;感觉写的相对来说还是比较简短的&#xff0c;如果有什么写的不好或是不对…

简单的贪吃蛇代码,可上机运行

贪吃蛇无敌版&#xff0c;可穿墙&#xff0c;英文输入法小写字母wasd操作。 #include<stdio.h> #include<string.h> #include<windows.h> #include<time.h> #include<conio.h>#define up w #define down s #define left a #define right d #def…

cmd贪吃蛇(cmd贪吃蛇怎么做)

贪吃蛇代码-贪吃蛇的围墙代码怎么&#xff1f;贪吃蛇的围墙代码怎么写 哈哈……避邪[哈哈] 贪吃蛇在哪下载啊 我的工享里有 在dos环境下c语言编程编一个贪吃蛇游戏 程序设计及说明 该类规定游戏的范围大小。 Snake 用该类生成一个实例蛇 snake 该类用于实现对蛇的操作控制&…

C++实现cmd界面简单贪吃蛇游戏

贪吃蛇的玩法我想应该大家都是耳熟能详了。但是这游戏虽然简单&#xff0c;但是编写的难度对一个刚刚学完c,准备考研的苦逼大学生来说却是一件非常艰难的事情。 date:10月3日&#xff0c;国庆节的头3天&#xff0c;大家在外玩耍我却苦逼的在这里写代码痛苦ing&#xff0c;不知…

手敲最基础C语言代码----“贪吃蛇”

C语言创作游戏----第二弹----贪吃蛇&#xff08;无限吃&#xff09; 主函数系列&#xff1a; 创建引入头文件----方便查看代码&#xff01;&#xff01; #include<stdio.h> #include<Windows.h> #include<stdlib.h> #include<conio.h> #include<tim…

创建链表和遍历链表算法演示

#include <stdio.h> #include <malloc.h> #include <string.h> #include <stdlib.h>typedef struct Node {int data; //数据域struct Node * pNext; //指针域}Node, *pNode;//函数声明 pNode create_list(); void traverse_list(pNode pHead); int…

C++ 创建链表

本文旨在解决两个问题&#xff1a; 1、如何写一个创建链表函数 2、为什么对于单个节点必须要new&#xff0c;而不能使用& 1、如何写一个创建链表函数 代码如下 ListNode* createListNode(vector<int> input) {ListNode dummy ListNode(-1);ListNode* pre &d…

单链表创建

单链表的创建与操作 链表作为基本的数据结构&#xff0c;学习好链表的创建与操作是数据结构入门的基础。 &#xff08;小白make for myself&#xff09; 单链表的创建 typedef struct Node {int data;struct Node* next; }Node;//结构体创建&#xff0c;也可以使用*Node取址…

动态链表的创建

#include <stdio.h> //List结构样式 typedef struct node { int data; struct node *next; }Node; //创建head的空链 Node *createList() { Node *head (Node *)malloc(sizeof(Node)); if(NULL head) exit(-1); head->next NULL; return head; } Node *insertList(…