Android MVVM框架搭建(一)ViewModel + LiveData + DataBinding

③ 实现登录

下面回到MainActivity中,增加代码如下图所示:

在这里插入图片描述

乍一看好像没啥不同的,无非就是给mainViewModel中的两个变量赋了值。不过这里有一个数据持久化的内容在里面,怎么证明呢?看一下下面这个GIF图

在这里插入图片描述

这个图可能有一些黑屏的地方,因为我在给自己的手机做横竖屏切换的时候,手机录屏好像有一点问题,不过没事。因为这个结果是对的,那就是数据持久化,因为我们知道手机在切换屏幕的时候Activity是会重新创建的,因此如果我们的数据是放在Activity中,那么切换屏幕之后就会重置,输入框也不会有值,但是通过ViewModel去保存输入框的值就不同了,虽然你的Activity在切换屏幕的时候销毁并且重新创建了,但是我的MainModel依然稳定,所以我才能在横屏的时候也登陆,这样不会造成数据丢失。

二、LiveData使用


LiveData是用来做什么的?数据变化感知,也就是说如果我一个页面中对一个TextView进行多次赋值的话,可以通过LiveData来操作,只需要在值改变的时候进行设置就好了,可以简化页面上的代码。下面举一个实际的例子来说明。依然是之前那个登录页面,不过需要修改一下MainViewModel中的变量,如下:

① 可修改数据

public MutableLiveData account = new MutableLiveData<>();

public MutableLiveData pwd = new MutableLiveData<>();

请注意这里使用的是MutableLiveData,表示值的内容开变动,而LiveData是不可变的。<>中的是泛型,你可以直接将一个对象放进去,当对象的内容有改动时,通知改变就可以了,现在这么写是为了方便理解。下面进入MainActivity中,首先我们改变一下布局activity_main.xml在按钮的下面再加如下代码

<TextView

android:id=“@+id/tv_account”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<TextView

android:id=“@+id/tv_pwd”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

② 数据观察

然后回到MainActivity中,修改代码如下图所示:

在这里插入图片描述

上面的图中从上往下有四处标注,我们从下面的两处标注来看,首先在给MainViewModel中的account赋值时,采用了MutableLiveData的setValue()的方式,还有一种方式是postValue(),这里要注意一点setValue()只能在主线程中调用,postValue()可以在任何线程中调用。pwd也是一样的,然后在最后一处标注的地方,对MainViewModel中的account和pwd进行数据观察,当这两个值有改变时通知页面最新的值,这里用了lambda表达式进行了一次简化,实际的代码是这样的。

在这里插入图片描述

下面我们运行一下:

在这里插入图片描述

三、DataBinding使用


Android的DataBinding在已经内置了,因此只需要在app模块的build.gradle中开启就可以使用了。DataBinding,顾名思义就是数据绑定,可以看到现在的三个组件都与数据有关系,ViewModel数据持有,LiveData数据观察、DataBinding数据绑定。

① 单向绑定

而DataBinding的绑定有两种方式:单向数据绑定和双向数据绑定。举个例子:比如我手机上收到一个通知,我需要显示通知的文字内容在页面上,这就是单向绑定,而我页面上的文字内容改变也重新发一个通知出去,这就是双向绑定。可以理解为A和B进行交互。A发消息,B要做出反应。B发消息,A也要相应改变。最常用的就是当我Model中的数据改变时,改变页面上的值。这个是单向绑定。下面我们可以新建一个用户User对象,代码如下:

public class User extends BaseObservable {

private String account;

private String pwd;

public String getAccount() {

return account;

}

public void setAccount(String account) {

this.account = account;

notifyChange();//通知改变 所有参数改变

}

public String getPwd() {

return pwd;

}

public void setPwd(String pwd) {

this.pwd = pwd;

}

public User(String account, String pwd) {

this.account = account;

this.pwd = pwd;

}

}

这里我继承了BaseObservable,注意它在androidx.databinding包下。然后我们的数据是需要显示在页面上的,而之前是通过Activity获取xml中的控件,然后显示数据在控件上,而现在有了DataBinding,可以直接和xml的中数据进行绑定,这看起来和JS比较像。下面我们对activity_main.xml进行改变。改变后代码如下:

<?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”

xmlns:tools=“http://schemas.android.com/tools”>

<variable

name=“user”

type=“com.llw.mvvm.User” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:gravity=“center”

android:orientation=“vertical”

android:padding=“32dp”

tools:context=“.MainActivity”>

<com.google.android.material.textfield.TextInputLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

<com.google.android.material.textfield.TextInputEditText

android:id=“@+id/et_account”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:hint=“账号” />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“12dp”>

<com.google.android.material.textfield.TextInputEditText

android:id=“@+id/et_pwd”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:hint=“密码”

android:inputType=“textPassword” />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.button.MaterialButton

android:id=“@+id/btn_login”

android:layout_width=“match_parent”

android:layout_height=“48dp”

android:layout_margin=“24dp”

android:insetTop=“0dp”

android:insetBottom=“0dp”

android:text=“登 录”

app:cornerRadius=“12dp” />

<TextView

android:id=“@+id/tv_account”

android:text=“@{user.account}”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<TextView

android:id=“@+id/tv_pwd”

android:text=“@{user.pwd}”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

这里我在最外层加了一个layout标签,然后将原来的布局放在layout里面,再增加一个数据源,也就是user对象,然后再底部的两个tv_account和tv_pwd两个TextView中的text属性中绑定了user对象中的属性值。当然这样还没有完成,最后一步是在MainActivity中去进行绑定的。

进入MainActivity。在onCreate方法中,先将其他的代码注释掉。

在这里插入图片描述

然后修改待明日如下图所示

在这里插入图片描述

这里要注意一点,DataBindingUtil.setContentView返回的是一个ViewDataBinding对象,这个对象的生成取决于你的Activity,例如MainActivity,就会生成ActivityMainBinding。然后再通过生成的ActivityMainBinding去设置要显示在xml中控件的值。因此你会看到我完全没有去findViewById,然后控件再去设置这个setText。还有一点就是当你使用了DataBinding之后就不需要去手动findViewById了,通过编译时技术会生成驼峰命名的对象,如上图的btnLogin、etAccount、etPwd。上图的代码就是通过更改数据然后通知到xml做更改,初始化的修改时admin、123456。然后再通过输入框去修改。我将会输入study、666,然后点击登录按钮,也会将输入框的数据显示在TextView上,这样是否会省去很多不必要的繁琐工作呢?下面运行一下:

在这里插入图片描述

② 双向绑定

双向绑定是建立在单向绑定的基础上,实际的开发中用到双向绑定的地方并没有单向绑定多,双向绑定举一个例子,在输入框输入数据时候直接将数据源中的数据进行改变,这里会用到ViewModel和LiveData。下面进行双向绑定的使用,修改一下MainViewModel,代码如下:

public class MainViewModel extends ViewModel {

public MutableLiveData user;

public MutableLiveData getUser(){

if(user == null){

user = new MutableLiveData<>();

}

return user;

}

}

下面修改User类,这里面做了一些改变

public class User extends BaseObservable {

public String account;

public String pwd;

@Bindable

public String getAccount() {

return account;

}

public void setAccount(String account) {

this.account = account;

notifyPropertyChanged(BR.account);//只通知改变的参数

}

@Bindable

public String getPwd() {

return pwd;

}

public void setPwd(String pwd) {

this.pwd = pwd;

notifyPropertyChanged(BR.pwd);//只通知改变的参数

}

public User(String account, String pwd) {

this.account = account;

this.pwd = pwd;

}

}

不同于notifyChange()改变某一个参数,某一个对象都会通知,现在notifyPropertyChanged()就具有针对性,只通知对应属性改变。之前在activity_main.xml中的data标签中是使用的User,现在我们改成ViewModel,顺便把布局调整一下,代码如下:

<?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”

xmlns:tools=“http://schemas.android.com/tools”>

<variable

name=“viewModel”

type=“com.llw.mvvm.viewmodels.MainViewModel” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:gravity=“center”

android:orientation=“vertical”

android:padding=“32dp”

tools:context=“.MainActivity”>

<TextView

android:id=“@+id/tv_account”

android:text=“@{viewModel.user.account}”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<TextView

android:layout_marginBottom=“24dp”

android:id=“@+id/tv_pwd”

android:text=“@{viewModel.user.pwd}”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<com.google.android.material.textfield.TextInputLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

<com.google.android.material.textfield.TextInputEditText

android:id=“@+id/et_account”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:text=“@={viewModel.user.account}”

android:hint=“账号” />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“12dp”>

<com.google.android.material.textfield.TextInputEditText

android:id=“@+id/et_pwd”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:text=“@={viewModel.user.pwd}”

android:hint=“密码”

android:inputType=“textPassword” />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.button.MaterialButton

android:id=“@+id/btn_login”

android:layout_width=“match_parent”

android:layout_height=“48dp”

android:layout_margin=“24dp”

android:insetTop=“0dp”

android:insetBottom=“0dp”

android:text=“登 录”

app:cornerRadius=“12dp” />

这里要注意点的地方有几个,第一个是数据源,这里绑定的是ViewModel,那么相对应的ViewModel中的数据数据都可以拿到。

在这里插入图片描述

第二个就是响应的地方,通过这种方式去显示ViewModel中对象的变量数据在控件上。这里我把这两个TextView放到输入框的上方

在这里插入图片描述

第三个地方,也是双向绑定的意义,就是UI改变数据源。我们都知道当输入框输入时,text属性值会改变为输入的数据,而@={viewModel.user.account}就是将输入的数据直接赋值给数据源。这样在Activity中我们将不需要去进行输入框的处理,减少了耦合。

在这里插入图片描述

下面让我们回到MainActivity中。修改代码后如下:

private ActivityMainBinding dataBinding;

private MainViewModel mainViewModel;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//数据绑定视图

dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

mainViewModel = new MainViewModel();

//Model → View

User user = new User(“admin”, “123456”);

mainViewModel.getUser().setValue(user);

//获取观察对象

MutableLiveData user1 = mainViewModel.getUser();

user1.observe(this, user2 -> dataBinding.setViewModel(mainViewModel));

dataBinding.btnLogin.setOnClickListener(v -> {

if (mainViewModel.user.getValue().getAccount().isEmpty()) {

Toast.makeText(MainActivity.this, “请输入账号”, Toast.LENGTH_SHORT).show();

return;

}

if (mainViewModel.user.getValue().getPwd().isEmpty()) {

Toast.makeText(MainActivity.this, “请输入密码”, Toast.LENGTH_SHORT).show();

return;

}

Toast.makeText(MainActivity.this, “登录成功”, Toast.LENGTH_SHORT).show();

});

}

结尾

最后,针对上面谈的内容,给大家推荐一个Android资料,应该对大家有用。

首先是一个知识清单:(对于现在的Android及移动互联网来说,我们需要掌握的技术)

泛型原理丶反射原理丶Java虚拟机原理丶线程池原理丶
注解原理丶注解原理丶序列化
Activity知识体系(Activity的生命周期丶Activity的任务栈丶Activity的启动模式丶View源码丶Fragment内核相关丶service原理等)
代码框架结构优化(数据结构丶排序算法丶设计模式)
APP性能优化(用户体验优化丶适配丶代码调优)
热修复丶热升级丶Hook技术丶IOC架构设计
NDK(c编程丶C++丶JNI丶LINUX)
如何提高开发效率?
MVC丶MVP丶MVVM
微信小程序
Hybrid
Flutter

接下来是资料清单:(敲黑板!!!


1.数据结构和算法

2.设计模式

3.全套体系化高级架构视频;七大主流技术模块,视频+源码+笔记

4.面试专题资料包(怎么能少了一份全面的面试题总结呢~)

不论遇到什么困难,都不应该成为我们放弃的理由!共勉~

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
框架结构优化(数据结构丶排序算法丶设计模式)

APP性能优化(用户体验优化丶适配丶代码调优)
热修复丶热升级丶Hook技术丶IOC架构设计
NDK(c编程丶C++丶JNI丶LINUX)
如何提高开发效率?
MVC丶MVP丶MVVM
微信小程序
Hybrid
Flutter

[外链图片转存中…(img-IKWWhjkj-1714397292163)]

接下来是资料清单:(敲黑板!!!


1.数据结构和算法

[外链图片转存中…(img-0jebO61U-1714397292164)]

2.设计模式

[外链图片转存中…(img-IhmxSGX2-1714397292166)]

3.全套体系化高级架构视频;七大主流技术模块,视频+源码+笔记

[外链图片转存中…(img-VS7irHDI-1714397292167)]

4.面试专题资料包(怎么能少了一份全面的面试题总结呢~)

[外链图片转存中…(img-EcXYahRq-1714397292168)]

不论遇到什么困难,都不应该成为我们放弃的理由!共勉~

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

[外链图片转存中…(img-1zHJyIp7-1714397292170)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 29
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值