Android中级——MVVM

news2024/11/19 12:31:34

MVVM

  • MVVM是什么?
  • MVVM实现
    • 前提
    • Model
    • ViewModel
    • View

MVVM是什么?

Model-View-ViewMode架构,可看作MVP改进版,将此前Presenter的逻辑操作交给ViewMode中的Binder去处理

在这里插入图片描述

  • Mode:封装数据存储及相关操作逻辑,与MVC/MVP不同的是会提供一系列实体类与UI绑定,ViewModel修改这些数据后将数据变化告诉View
  • View:处理界面逻辑但不参与业务逻辑,显示ViewModel提供的数据
  • ViewModel:视图模型与视图状态的合称,为View提供一个可供显示的数据模型并收集、处理这些数据,内部的Binder用于双向绑定,还可包含多个Child ViewModel

MVVM实现

前提

在build.gradle中android节点添加如下代码(最低SDK版本为API7,Gradle版本为1.5.0-alpha1)

dataBinding{
    enabled = true
}

Model

创建数据实体类LoginInfo

  • 继承BaseObservable
  • getXXX()方法通过@Bindable注解表示该方法所返回的数据被修改时会更新UI
  • setXXX()方法调用notifyPropertyChanged()告诉DataBinding该字段被更改
public class LoginInfo extends BaseObservable {
    private String mUser;
    private String mPassword;

    public LoginInfo(String user, String password) {
        mUser = user;
        mPassword = password;
    }

    @Bindable
    public String getUser() {
        return mUser;
    }

    public void setUser(String user) {
        mUser = user;
        notifyPropertyChanged(BR.user);
    }

    @Bindable
    public String getPassword() {
        return mPassword;
    }

    public void setPassword(String password) {
        mPassword = password;
        notifyPropertyChanged(BR.password);
    }
}

ViewModel

LoginModel封装维护LoginInfo、点击事件、文本改变事件

public class LoginModel {
    private static final String DEF_USER = "song";
    private static final String DEF_PASSWORD = "123";
    public LoginInfo mInfo;
    private OnLoginListener mListener;

    public LoginModel(OnLoginListener listener) {
        mListener = listener;
        mInfo = new LoginInfo("", "");
    }

    public TextWatcher getUserTextWatcher() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                mInfo.setUser(s.toString());
            }
        };
    }

    public TextWatcher getPasswordTextWatcher() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                mInfo.setPassword(s.toString());
            }
        };
    }

    public interface OnLoginListener {
        void onLoginSuccess();

        void onLoginFail();
    }

    public void onLoginClick(View view) {
        if (mInfo.getUser().equals(DEF_USER) && mInfo.getPassword().equals(DEF_PASSWORD)) {
            mListener.onLoginSuccess();
        } else {
            mListener.onLoginFail();
        }
    }
}

View

xml文件根节点变为layout,布局分为

  • 数据部分:声明所使用到的数据实体类以及构造该对象时的引用名
  • UI部分:常规控件,可直接使用数据实体类对象中的字段、方法
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="model"
            type="com.demo.demo0.LoginModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:addTextChangedListener="@{model.getUserTextWatcher}"
            android:hint="User"
            android:text="@{model.mInfo.getUser}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:addTextChangedListener="@{model.getPasswordTextWatcher}"
            android:hint="Password"
            android:text="@{model.mInfo.getPassword}" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{model.onLoginClick}"
            android:text="Login" />
    </LinearLayout>

</layout>

MainActivity开启线程3秒后修改数据会显示在UI

  • 通过DataBindingUtil.setContentView设置布局,布局名字为R.layout.ab_cd,则对应类为AbCdBinding,为其设置Model
public class MainActivity extends AppCompatActivity implements LoginModel.OnLoginListener {
    private static final String TAG = "MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        LoginModel model = new LoginModel(this);
        binding.setModel(model);
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);
                model.mInfo.setUser("New User");
                model.mInfo.setPassword("New Password");
            }
        }).start();
    }
    
    @Override
    public void onLoginSuccess() {
        Log.d(TAG, "onLoginSuccess: ");
    }
    
    @Override
    public void onLoginFail() {
        Log.d(TAG, "onLoginFail: ");
    }
}

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

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

相关文章

LeetCode 799. 香槟塔【数组,模拟,简单线性DP】1855

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Py之tiktoken:tiktoken的简介、安装、使用方法之详细攻略

Py之tiktoken&#xff1a;tiktoken的简介、安装、使用方法之详细攻略 目录 tiktoken的简介 1、性能&#xff1a;tiktoken比一个类似的开源分词器快3到6倍 tiktoken的安装 tiktoken的使用方法 1、基础用法 (1)、用于OpenAI模型的快速BPE标记器 (2)、帮助可视化BPE过程的代…

【SA8295P 源码分析 (三)】97 - QNX AIS Camera 框架介绍 及 Camera 工作流程分析

【SA8295P 源码分析】97 - QNX AIS Camera 框架介绍 及 Camera 工作流程分析 一、QNX AIS Server 框架分析二、QNX Hypervisor / Android GVM 方案介绍三、Camera APP 调用流程分析四、QCarCam 状态转换过程介绍五、Camera 加串-解串 硬件链路分析六、摄像头初始化检测过程介绍…

观察者模式-对象间的联动

有个商城小程序&#xff0c;用户希望当有新品上市的时候能通知他们。这样用户就可以不要时刻盯着小程序了。在这个场景中&#xff0c;用户向小程序订阅了一个服务——发送新品短信。小程序在有新品上线时负责向订阅客户发出这个消息。 这就是发布-订阅模式&#xff0c;也称观察…

YOLOv5-调用官方权重进行检验(目标检测)

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营-第7周&#xff1a;咖啡豆识别&#xff08;训练营内部成员可读&#xff09; &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https…

运放的单电源供电设计

文章目录 运放单电源供电同向比例单电源放大电路设计反向比例单电源放大电路设计 运放单电源供电 同向比例单电源放大电路设计 不放大直流&#xff0c;对直流来说是一个电压跟随器&#xff0c;对交流来说是同向比例 反向比例单电源放大电路设计 注&#xff1a;仪表放大器不能直…

Redis内存回收机制-内存淘汰策略和过期策略

Redis是基于内存操作的非关系型数据库&#xff0c;在内存空间不足的时候&#xff0c;为了保证程序的运行和命中率&#xff0c;就会淘汰一部分数据。如何淘汰数据&#xff1f;这就是Redis的内存回收策略。 Redis中的内存回收策略主要有两个方面&#xff1a; Redis过期策略&#…

nodejs+vue云旅青城系统-旅游网站

用户可以实现首页、个人中心、订票信息管理、路线制定管理等。不仅使服务管理难度变低了&#xff0c;还提升了管理的灵活性。目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 …

【四:Spring整合Junit】

目录 相同点不同点1、导入依赖增加2、编写的位置不同。。路径一定要与实现类一致 相同点 前面都一样和Spring整合mybatis&#xff08;基于注解形式&#xff09;一样Spring整合Mybatis 不同点 1、导入依赖增加 <!-- 单元测试 --><dependency><groupId>junit&…

【MySql】8- 实践篇(六)

文章目录 1. MySql保证主备一致1.1 MySQL 主备的基本原理1.2 binlog 的三种格式对比1.3 循环复制问题 2. MySql保证高可用2.1 主备延迟2.2 主备延迟的来源2.3 可靠性优先策略2.4 可用性优先策略 3. 备库为何会延迟很久-备库并行复制能力3.1 MySQL 5.6 版本的并行复制策略3.2 Ma…

Unity之ShaderGraph如何实现马赛克效果

前言 今天我们来实现一个马赛克的效果 如下所示&#xff1a; 关键节点 Posterize&#xff1a;色调分离节点 图像的色调分离或色调分离需要将色调的连续渐变转换为色调较少的几个区域&#xff0c;并从一种色调突然改变为另一种色调。 原理 原理就是通过色调分离节点&…

华纳云:linux怎么搭建node.js开发环境

搭建Node.js开发环境在Linux系统上非常简单&#xff0c;以下是一些基本步骤&#xff0c;以帮助您开始&#xff1a; 1. 安装Node.js&#xff1a; 您可以通过包管理器来安装Node.js。不同的Linux发行版使用不同的包管理器。以下是一些常见的Linux发行版和它们的包管理器&#xff…

虚拟音频设备软件 Loopback mac中文版软件介绍

创建虚拟音频设备以从应用程序和音频输入设备获取声音&#xff0c;然后将其发送到音频处理应用程序&#xff0c;它就是—Loopback for Mac&#xff0c;Loopback mac为您提供高端工作室混音板的强大功能&#xff0c;有了它在Mac上传递音频会变得很容易。 Loopback for mac中文版…

Paper Reading:《Consistent-Teacher: 减少半监督目标检测中不一致的伪目标》

#pic_center 550x200 目录 简介工作重点方法ASA, adaptive anchor assignmentFAM-3D, 3D feature alignment moduleGMM, Gaussian Mixture Model实施细节 实验与SOTA的比较消融实验 总结 简介 题目&#xff1a;《Consistent-Teacher: Towards Reducing Inconsistent Pseudo-ta…

Flutter开发GridView控件详解

GridView跟ListView很类似&#xff0c;Listview主要以列表形式显示数据&#xff0c;GridView则是以网格形式显示数据&#xff0c;掌握ListView使用方法后&#xff0c;会很轻松的掌握GridView的使用方法。 在某种界面设计中&#xff0c;如果需要很多个类似的控件整齐的排列&…

AI绘画的魅力与未来:人工智能如何重塑艺术创作

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;AI绘画已经成为艺术与技术交汇的新领域。通过深度学习、神经网络等先进技术&#xff0c;AI不仅能理解和模拟人类艺术家的创作风格&#xff0c;还能生成令人惊叹的原创艺术作品。本文旨在探讨AI绘画的现状、挑…

单点登录是什么?

单点登录&#xff08;Single Sign On, SSO&#xff09;是指在同一帐号平台下的多个应用系统中&#xff0c;用户只需登录一次&#xff0c;即可访问所有相互信任的应用系统。 单点登录的本质就是在多个应用系统中共享登录状态。如果用户的登录状态是记录在 Session 中的&#xff…

“构建交互式用户界面的自定义组件应用与界面布局设置“

目录 引言自定义组件应用设置界面布局投票界面布局及实现投票选项界面总结 引言 在软件开发中&#xff0c;用户界面设计是至关重要的一环。良好的界面设计可以提升用户体验、增加用户黏性&#xff0c;并提高软件的易用性。本篇博客将介绍如何利用自定义组件应用和界面布局设置…

【自动化测试入门】用Airtest - Selenium对Firefox进行自动化测试(0基础也能学会)

1. 前言 本文将详细介绍如何使用AirtestIDE驱动Firefox测试&#xff0c;以及脱离AirtestIDE怎么驱动Firefox&#xff08;VScode为例&#xff09;。看完本文零基础小白也能学会Firefox浏览器自动化测试&#xff01;&#xff01;&#xff01; 2. 如何使用AirtestIDE驱动Firefox…

地铁大数据客流分析系统 设计与实现 计算机竞赛

文章目录 1 前言1.1 实现目的 2 数据集2.2 数据集概况2.3 数据字段 3 实现效果3.1 地铁数据整体概况3.2 平均指标3.3 地铁2018年9月开通运营的线路3.4 客流量相关统计3.4.1 线路客流量排行3.4.2 站点客流量排行3.4.3 入站客流排行3.4.4 整体客流随时间变化趋势3.4.5 不同线路客…