Android入门第59天-进入MVVM

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

什么是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)的设计模式动不动就是一堆的ViewHoldergetView还要避免二次重复加载......

这一切其实在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形式。

所以MVVMModel 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的控件的值也给改变了。

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

附、项目工程全结构

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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android