Android入门第59天-进入MVVM

news2024/11/15 8:58:22

什么是MVVM

用“某大文豪亲”的话说:MVVM并不存在,只是xml里找控件找了太多了,自然而然就“找”出了一套共性

所以,MVVM只是包括了以下这些技术:

  1. DataBind;

  1. ViewModel双向绑定;

  1. Okhttp3+retrofit+rxjava(时下最流行,我们后续教程会让学这个东西变得简单到极致);

  1. 其它非Android Studio内提供的一些控件、工具类的使用;

以上这一套又有人称为:Google Android Jetpack

为什么传统的开发不用要去用MVVM?

首先让我们来看一下,传统的android开发我们会经常干一些什么样的事呢?

先定义一个layout布局,然后对控件设定android:id,然后在Activity的java端去做findViewById(R.id.myButton)这样找到这个控件,再然后。。。再然后。。。

再来看我们使用DataAdapter(MVC)的设计模式,动不动就是一堆的ViewHolder,getView还要避免二次重复加载......

这一切其实在Android的底层是根据一个xml格式的layout加载然后使用xml path路径查询去定位和绑定到我们的控件的。各位有Java Xml编程经验的都知道,xml的dom查找费时又费力,有时xml的层次嵌套一多还会出现性能问题

因此呢,google就想在编译时就把这个xml一次转成一个Java的Object然后使用Java的内部支持的LinkList、ArrayList、HashMap等数据结构去实现这些定位,不是更优雅、更便捷、更“程序员”么?于是就产生了Data Binding。

那么有了Data Binding后,我们还要考虑诸如此类场景:譬如说我在界面有一个EditText,往里面录入了值,然后在点击一个【提交】按钮时,要把这个刚录进去的文字内容给取出来?那么换了平时我们需要先定位到这个控件->再把这个控件当前的内容取出来->赋给一个局部变量。有时如果碰到横坚屏切换,如果我们要保持输入的EditText内的内容保持不被clean掉还需要做二次赋值、二次查找控件,是不是?

那么现在假设我们可以让控件和这个临时局部变量和这个EditText的onChanged事件对开发时来说变得“透明”,每次set/get就可以了,让底层框架去实现这些控件定位、查找、二次赋值等工作,于是就有了ViewModel形式。

所以MVVM(Model View ViewModel)就这么来了!

当然,有了上述这些我们还要考虑如:Fragment里怎么MVVM、Activity里怎么MVVM、ImageView怎么MVVM、最常用的HttpJson Request怎么MVVM?

于是为了隐藏、掩盖极大便利开发者,把一些对“底层”的协议部分的转换、重复的劳动去除掉,这就有了什么Glide、Okhttp3+retrofix+rxjava这些东西了。

把这些东西打包在一起就成了google jetpack。

因此,一切都是源于“减少重复、无意义的劳动”而诞生的。大家可以认为MVVM就是J2ee->struts->this is not j2ee(spring)->spring+hibernate->jfx->spring+mybatis->spring boot->spring boot2这么一个演变过程中的产物而己。它并不是什么新的理念,也没有什么高的技术含量,它只是“因为开发的人多了、平时碰到的一些重复性劳动成为了共通的痛点后人们进行了总结、抽象”后的一个产物而己。

Android的学习路径

在进入正文前,我们的Android到今天为此算是一个里程碑,因为如果你不学后面的40多天,你其实已经自己可以开发点东西了,自己照着微博留言做一个小论坛、小商城,前面我们学习到的这些知识足够用了。但是,如果你想去正规化团队、好点的团队、公司工作肯定不能这么“作坊”,那么后面我们就会集中火力讲在jetpack即MVVM模式下的各种开发了。

所以,有必要先列一下什么称为学好Android需要经历哪些核心知识点。你也可以跳过这一节直接进入后续篇章,我是按照一个小白以及教学上从易入难、一个程序员是怎么培养的(从感性到理性)的一惯手法列出了下面共计:16大类、63个技术点,这也是我们这个系列遵照的一条写作线索。

当一个人把这些内容全学完了,Android才可以算是入门了(对不起,我从不说高手一类,因为高手是指哪些发明了Android的人,因此我到现在为止还一直称自己是合格的程序员,高级也不算。只有发明开发了那些mysql、linux、java语言的人才称得上真正的高级程序员)说白了就是可以找个好点的厂子了

Android学习路线一览

一、开始阶段

  1. 新建工程

  1. 环境相关知识

二、基本布局

  1. LinearLayout

  1. TableLayout

  1. RelativeLayout

  1. 几个基本布局的混用

三、基本组件与Android开发基础知识

  1. TextView

  1. EditText

  • 监听回车

  • 光标移动和选择

  1. Button

  1. ImageView

  1. ProgressBar

  1. RadioButton

  1. CheckBox

  1. SwitchButton

  1. SeekBar

  1. StatusBar

  1. WebView

  1. RecycleViews

  1. DrawerLaout

  1. 自定义View

  1. 模块化基本知识

  1. Gradle

  1. NDK

  1. 调试机巧

  1. 一些常用第三方库

  1. 多线程

  1. IO

  1. Network相关基本知识

四、Activity相关

  1. Android Activity是干什么的

  1. Activity生命周期

  1. Activity的启动以及携带参数启动

五、Service

  1. Service是干什么的

  1. 后台Service

  1. 前台Service

  1. IntentService用法

六、BroadCast

  1. 广播机制BroadCast的介绍

  1. 监听屏幕亮灭

七、Fragment

  1. Fragment基本概念

  1. Fragment的使用

八、res的应用

  1. 资源目录的使用

  1. Shape的绘制

  1. Android组件的一些自定义图片、背景

九、Android权限

十、字体

  1. Text Style

  1. Android的字库

十一、数据库

十二、设计模式

  1. MVC

  1. MVVM

十三、Android JetPack全家桶

  1. 介绍

  1. Fragment间共享数据

  1. DataBind

  • 使用

  • 数据绑定

  • 对于ObserableFiled以及可观察对象的使用

  1. Live Data

  • 数据准备

  • Layout

  • Activity设计

  1. LifeCycle

  • 活动

  • 状态转换

  1. WorkManager

  • 入门

  • Work Manager工作约束、延迟与查询

  • Work Manager定时任务

  1. View Model

  • 概览

  • Activity使用View Model

十四、编译打包CICD以及监控相关

十五、动画基础

十六、与设备相关开发

  1. 像机

  1. 蓝牙

  1. Wifi

  1. 获取手机的角度、姿势

  1. AIDL

  1. ZIP

  1. Binder

  1. Notification

  1. RTFSC

  1. PackManager

MVVM-之从DataBind入门

我们假设我们有一个Login界面,里面就3个内容,如下图中所示。

  • user.name

  • user.password

  • user.header

然后点击一下【CLICK]按钮,把user.name和user.password里的内容变换成我们预设的另一个人的信息。

从传统的开发来说我们需要有两个TextView+一个ImageView,是不是?

现在我们用MVVM的DataBind是怎么实现的呢?

DataBind第一步-工程需要变成可以DataBind

在build.gradle里加入如下内容,一定不要忘了,记得它是加在android{}块内的

    dataBinding {
        enabled = true
    }

DataBind第二步-build.properties内要启用google jetpack

在gradle.properties里加入以下两句话

android.useAndroidX=true
android.enableJetifier=true

还没完,接着把这个工程->Migrate to AndroidX,切记,否则后面你在学ViewModel时会碰到一堆很“怪”的问题,其实归根到底是因为我们前面一直用的都是android.v4.support的package,而MVVM里用到的都是androidx包内的内容,就算具体的类名相同其属性和相关的成员函数还是有不少区别的。从现在开始我们就要开始习惯于androidx了,如下截图操作:

选中你的工程->File->Refactor->Migrate to AndroidX。在Migrate时android studio会提示你备份好原有的项目,你可以选“Y”也可以选“Ignore”,看个人喜好吧。

DataBinding第三步-什么都正常的情况下出现了一堆红色的problem的处理手段

这一步后会提示项目重启,反正在新建项目时把这一步纳入第三步,这样一次干净的重启后顺达便项目进行了重编译、顺达便也就把一堆的gradle需要的依赖包给下下来了。

DataBinding第四步-Layout或者是activity的布局文件里要使用<layout>标签

如果我们已经有一个layout布局了,我们需要把我们的最最外层的xml的根结点,用layout替换成如下样例中的内容:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

改完后的一个标准的xml的layout内容如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <!-- 设置数据源 data中可以添加多个数据源 -->
    <data>
        <variable
            name="user"
            type="com.mkyuan.android.demo.simplemvvm.User" />
    </data>
    <!-- 我们自己的布局 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <!--
         数据设置采用上面设置的name.属性的方式
         这里是 user.name
         如果想拼接字符串使用的是键盘左上角数字1旁边的那个符号
         "@{`拼接字符串`+user.name}"
         -->
        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{`姓名:`+user.name}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{`密码:`+user.password}" />
        <ImageView
            android:adjustViewBounds="true"
            android:layout_width="150dp"
            android:layout_height="200dp"
            app:headId="@{user.header}" />

        <Button
            android:id="@+id/buttonChangeUserInfor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="click"
            android:text="click" />

    </LinearLayout>
</layout>

DataBinding第五步-定义一个extends BaseObservable的Java POJO

拿我们的例子,这个界面有3个属性,一个是user.name,一个是user.password,一个是user.header。

package com.mkyuan.android.demo.simplemvvm;
/**
 * User 实体类
 * mvvm 绑定的步骤如下:
 * <p>
 * 1.User类继承被观察者的一个类 BaseObservable androidx.databinding包下面的一个类(我是使用的androidx)
 * 2.get方法添加  @Bindable 注解,这是一个运行时注解。
 * 3.在需要同步属性的set方法中设置对应的值 如setName中:notifyPropertyChanged(BR.name); 其中 BR是编译时生成的一个类,没有的话可以rebuild一下
 * 这样一个基本的数据绑定就结束了
 */

import android.widget.ImageView;

import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.databinding.BindingAdapter;

import com.bumptech.glide.Glide;

import java.time.Instant;

public class User extends BaseObservable {
    public User(String name, String password,int header) {
        this.name = name;
        this.password = password;
        this.header=header;
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

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

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

    private int header;
    @Bindable
    public int getHeader() {
        return header;
    }

    public void setHeader(int header) {
        this.header = header;
        notifyPropertyChanged(BR.header);
    }
    //自定义属性  headUrl 是自定义的,在xml的imageView中引用
    @BindingAdapter("headId")
    public static void getImage(ImageView view, int headerId) {
        Glide.with(view.getContext()).load(headerId).into(view);
    }

    private String name = "";
    private String password = "";
}

此处我们使用了Glid,这是一个优化过的并且简化了的把远程/本地图片塞到ImageView的组件。要使用它你需要在gradle中加入以下的依赖

    implementation 'com.github.bumptech.glide:glide:4.9.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'

核心代码解读

  1. @Bindable对象,它必须定义在getXXX方法上,它的作用等同于findViewById、find到后取控件、得到控件后取控件的相关属性、把控件相关属性里的value赋到一个临时变量这么一个作用;

  1. notifyPropertyChanged(),它就相关于findViewById、找到控件后获取用户刚输入的那个内容、监听这个控件的onChanged事件,并且把这个刚输入的内容再替换之前get出来的内容赋给到的临时变量里的值的作用;

  1. @BindingAdapter("headId"),介个就是对ImageView的databinding的用法了。它的作用就是绑定你的activity_main.xml文件里的ImageView对象,并使用Glide组件优雅的把一个本地(也可以是远程)Image(的ID)喂入ImageView里并显示成图片;

DataBinding正式使用

没有第六步了,第六步就是使用了,我们来看我们的Activity的交互端代码MainActivity.java

package com.mkyuan.android.demo.simplemvvm;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

import android.os.Bundle;
import android.view.View;


import com.mkyuan.android.demo.simplemvvm.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "DemoSimpleMVVM";
    private ActivityMainBinding activityMainBinding;

    public void click(View view) {
        int imageId=R.drawable.qq;
        activityMainBinding.getUser().setName("李四");
        activityMainBinding.getUser().setPassword("password123");
        activityMainBinding.getUser().setHeader(imageId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 通过 DataBindingUtil 的 setContentView 方法替代 activity 的 setContentView 方法,返回
        // ActivityMainBinding
        activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        int imageId=R.drawable.header;
        User user = new User("张三", "123456",imageId);
        // 通过 ActivityMainBinding 将数据源和view绑定
        activityMainBinding.setUser(user);
    }
}

看这个代码,从头到位有没有findViewById?

另外代码中我们可以看到有一个叫ActivityMainBinding的类,这个是哪来的?

我们看我们的项目中是不是一个activity就有一个叫activity_名字.xml的文件。那么我们在第四步中,在activity_main.xml文件里不是把最顶层的标签加了<Layout>以及相应的data的绑定了是不是?于是,AndroidStudio就自动会把这个activity_main.xml做以下操作:

  1. 去掉_xml;

  1. 把.xml前的用java驼峰命名方式连接_(下划线)前后的单词把这些单词大写+Binding并生成这个类(如果有一些开发者在AndroidStudio里没有生成这个类,那么你可以:Build->Rebuild Project一下)

然后你自己运行一下试试看这个效果,一个click按钮点下去,看似你在替换的是User这个类里的值实际Databind里把你的主界面里的user.name、user.password、user.header相binding的控件的值也给改变了。

是不是?嘿嘿!很好看吧?不妨自己动一下手试试看吧。

附、项目工程全结构

风雨虽大、但有你我携手“共撑一把伞”才能安然渡过。分享知识、便利你我、创造共赢!

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

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

相关文章

图解函数递归、数组详解

目录 一.修炼必备 二.图解递归的执行过程 三.数组 3.1 一维数组 3.2 二维数组 3.3 数组的共同问题 一.修炼必备 1.入门必备&#xff1a;VS2019社区版&#xff0c;下载地址&#xff1a;Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com) 2.趁手武…

视频文缩略图SDK:GleamTech VideoUltimate Crack

Video Reader and Thumbnailer for .NET Core 和 .网络框架 读取地球上的任何视频文件格式。逐帧读取视频文件。生成有意义的缩略图。 VideoUltimate是最快&#xff0c;最简单的.NET视频阅读器和缩略图器&#xff0c;可以读取任何视频文件格式 在地球上。它允许您逐帧读取视频…

C++ 一文解决 数据库ODB 安装/调试/使用的问题

引用&#xff1a; ODB Download (codesynthesis.com) Installing ODB on Linux/UNIX (codesynthesis.com) 缘起&#xff1a; 在开发过程中发现&#xff0c;现有的软件缺乏持久层&#xff08;Persistence Layer&#xff09;&#xff0c;即专注于实现数据持久化应用领域的某个…

广义零样本学习的转移增量

摘要&#xff1a;零样本学习&#xff08;ZSL&#xff09;是一种成功的从未知类中对对象进行分类的范例。然而&#xff0c;它在广义零样本学习&#xff08;GZSL&#xff09;设置中遭受严重的性能降级&#xff0c;即以识别来自可见类和不可见类的测试图像。在本文中&#xff0c;为…

C语言-qsort函数基本使用

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C/C】 先来看一下qsort函数的介绍&#xff1a; Compare 函数的返回值描述>0elem1将被排在elem2前面0elem1等于elem2<0elem1 将被…

LeetCode刷题模版:171-174、179

目录 简介171. Excel 表列序号172. 阶乘后的零173. 二叉搜索树迭代器174. 地下城游戏【未理解】179. 最大数结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,…

Redis学习【1】之Nosql概述

文章目录一 从技术发展探究使用Nosql的原因1.1 单机Mysql时代1.2 Memcached&#xff08;缓存&#xff09; MySQL 垂直拆分[读写分离]1.3 MySQL主从读写分离1.4 分表分库 水平拆分 Mysql 集群1.5 如今时代1.6 使用NoSQL的原因二 Nosql初识2.1 NoSQL的特点【解耦】三 NoSQL的四…

树状数组的原理和区间和

目录 一、前言 二、树状数组的原理 1、杂论 2、从二叉树到树状数组 3、神奇的 lowbit(x) 操作 4、tree[ ]数组&#xff1a;将一维信息转换为树形信息存储 5、基于 tree[ ] 的计算 6、tree[]的更新&#xff08;要加lowbit&#xff09; 三、树状数组的应用 1、单点修改…

流媒体方案之Nginx

1.Nginx可以作为流体服务器。2三种web服务器的比较3.推流端: FFmpeg使用RTMP协议向Nginx推流拉流端: •VLC播放器使用RTMP或HTTPFLV协议从Nginx拉流•浏览器使用HTTPFLV协议从Nginx拉流(安装flv.js)4.有两种方法&#xff1a;下载源码&#xff0c;手工编译使用Buildroot&#xf…

Redis分布式锁 | 黑马点评

目录 一、分布式锁概述 二、基于Redis的分布式锁 1、思路分析 2、初级版本 3、误删问题 4、改进分布式锁 5、原子性问题 6、使用Lua脚本解决原子性问题 7、setnx实现分布式锁存在问题 三、Redisson 1、Redisson快速入门 2、Redisson可重入锁原理 3、Redisson可重试…

从某一点出发沿任意一方向旋转矩阵计算思考与实现

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 上期讲到 绕任一向量旋转矩阵计算思考与实现 点击前往 点击前往 问题提出 之前讲到绕任一向量旋转矩阵实现&#xff0c;原来的向量都是从原点出发&#xff0c;现在把…

Ajax面试题目

更多Ajax面试题目可以查看专栏内容 1.AJAX应用和传统Web应用有什么不同&#xff1f; 传统的web前端与后端的交互中&#xff0c;浏览器直接访问Tomcat的Servlet来获取数据。Servlet通过转发把数据发送给浏览器。当我们使用AJAX之后&#xff0c;浏览器是先把请求发送到XMLHttpR…

Swift之struct二进制大小分析

随着Swift的日渐成熟和给开发过程带来的便利性及安全性&#xff0c;京喜App中的原生业务模块和基础模块使用Swift开发占比逐渐增高。本次讨论的是struct对比Class的一些优劣势&#xff0c;重点分析对包体积带来的影响及规避措施。 一、基础知识 1、类型对比 引用类型&#xff…

独立看门狗与窗口看门狗

定义 看门狗的本质是一个定时器&#xff0c;在启动后&#xff0c;需要在一定时间内再给它一个信号&#xff0c;俗称“喂狗”&#xff0c;如果没有按时“喂狗”&#xff0c;说明MCU可能处于非正常状态&#xff0c;这时看门狗就向MCU发送个复位信号&#xff0c;使整个系统重启&a…

51单片机数码管显示

文章目录前言一、数码管简介二、数码管原理图三、数码管显示原理四、静态数码管代表编写五、动态数码管总结前言 这篇文章将介绍数码管的显示其中包含了动态数码管和静态数码管两种。 一、数码管简介 数码管其实就是由多个发光二极管封装在一起组成“8”字型的器件当分别点亮…

【数据结构】超详细——堆的实现

一、堆的概念及性质 1.1 什么是堆&#xff1f; 堆是一种完全二叉树&#xff08;具体在下一章讲述&#xff09;&#xff0c;若二叉树的深度h&#xff0c;除了第h层外其余各层节点数满了&#xff0c;只有第h层缺额且该层结点靠左&#xff1b;任何一个数组可以看作完全二叉树&…

【14】C语言_函数简介

目录 1、C语言中函数的分类: 2、库函数 3、自定义函数 1、C语言中函数的分类: 1.库函数 2.自定义函数 2、库函数 为什么会有库函数? 1.我们知道在我们学习C语言编程的时候&#xff0c;总是在一个代码编写完成之后迫不及待的想知道结果&#xff0c;想把这个结果打印到我们的屏…

ESP32设备驱动-LX1972可见光传感器驱动

LX1972可见光传感器驱动 1、LX1972介绍 LX1972 是一款低成本硅光传感器,其光谱响应非常接近人眼。专利电路在 520nm 处产生峰值光谱响应,IR 响应小于峰值响应的 5%,高于 900nm。 光电传感器是一个 PIN 二极管阵列,具有线性、准确和非常可重复的电流传递函数。 芯片上的…

扫盲-从零开始搭建阿里云流媒体服务器/音视频编解码/

1.基础概念 2.简单模式-HTTP文件服务器 存储采用NAS&#xff0c;服务器配置 采用FASTDFS (192条消息) Linux新手入门系列&#xff1a;FastDFS单机部署一键安装脚本_IT小胖豆的博客-CSDN博客 有几个坑&#xff1a; 常用命令&#xff1a; tail -20f /usr/local/nginx/logs/er…

3小时精通opencv(三)图片裁剪与形状绘制

3小时精通opencv(三)图片裁剪与形状绘制 参考视频资源:3h精通Opencv-Python 文章目录3小时精通opencv(三)图片裁剪与形状绘制图片裁剪绘制形状绘制直线绘制矩形绘制圆形绘制文字整体代码图片裁剪 图片裁剪不需要使用opencv中特有的函数, 对于opencv中读取到的图像, 直接当做矩…