livedata mvvm

We’ve already implemented MVVM using Data Binding and covered LiveData and Data Binding in separate tutorials. Today, we’ll use LiveData with Data Binding in our MVVM Android Application. We’ll see how LiveData makes it easy to update the UI from the ViewModel.

我们已经使用数据绑定实现了MVVM ,并在单独的教程中介绍了LiveData和Data Binding 。 今天,我们将在MVVM Android应用程序中使用带有数据绑定的LiveData。 我们将看到LiveData如何使从ViewModel更新UI变得容易。

MVVM LiveData数据绑定 (MVVM LiveData Data Binding)

Up until now, we’ve used Data Binding to update the View from the ViewModel. LiveData is a handy data holder that acts as a container over the data to be passed. The best thing about LiveData is that it is lifecycle aware. So if you are in the background, the UI won’t try to update.

到目前为止,我们已经使用数据绑定从ViewModel更新视图。 LiveData是一个方便的数据持有者,充当要传递的数据的容器。 LiveData最好的事情是它具有生命周期意识。 因此,如果您在后台,则UI不会尝试更新。

This saves us from a lot of crashes at runtime.

这使我们免于在运行时发生大量崩溃。

We’ll use the MutableLiveData class since it provides public methods setValue() and getValue().

我们将使用MutableLiveData类,因为它提供了公共方法setValue()getValue()

Let’s create a simple Login Application using the above concepts. We will first use LiveData as well as Two-way Data Binding and then refactor the Data Binding Observables to LiveData completely.

让我们使用以上概念创建一个简单的Login Application。 我们将首先使用LiveData以及双向数据绑定,然后将数据绑定可观察对象完全重构为LiveData。

入门 (Getting Started)

Add the following dependency in your app’s build.gradle:

在应用程序的build.gradle中添加以下依赖项:

android {...dataBinding {enabled = true}...
}dependencies {...implementation 'android.arch.lifecycle:extensions:1.1.1'implementation 'com.android.support:design:28.0.0-beta01'...
}

项目结构 (Project Structure)

The LoginViewModelOld file would contain the old code and LoginViewModel file would contain the refactored code.

LoginViewModelOld文件将包含旧代码,而LoginViewModel文件将包含重构代码。

模型 (Model)

We’ve defined our Model in the User.java class:

我们已经在User.java类中定义了模型:

package com.journaldev.androidmvvmdatabindinglivedata;import android.util.Patterns;public class User {private String mEmail;private String mPassword;public User(String email, String password) {mEmail = email;mPassword = password;}public String getEmail() {if (mEmail == null) {return "";}return mEmail;}public String getPassword() {if (mPassword == null) {return "";}return mPassword;}public boolean isEmailValid() {return Patterns.EMAIL_ADDRESS.matcher(getEmail()).matches();}public boolean isPasswordLengthGreaterThan5() {return getPassword().length() > 5;}}

布局 (Layout)

The code for the activity_main.xml is given below:

下面给出了activity_main.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"xmlns:app="https://schemas.android.com/apk/res-auto"><data><variablename="loginViewModel"type="com.journaldev.androidmvvmdatabindinglivedata.LoginViewModel" /></data><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="8dp"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:error="@{loginViewModel.errorEmail}"app:errorEnabled="true"><EditTextandroid:id="@+id/inEmail"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Email"android:inputType="textEmailAddress"android:padding="8dp"android:text="@={loginViewModel.email}" /></android.support.design.widget.TextInputLayout><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:error="@{loginViewModel.errorPassword}"app:errorEnabled="true"><EditTextandroid:id="@+id/inPassword"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Password"android:inputType="textPassword"android:padding="8dp"android:text="@={loginViewModel.password}" /></android.support.design.widget.TextInputLayout><Buttonandroid:id="@+id/button"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:onClick="@{()-> loginViewModel.onLoginClicked()}"android:text="LOGIN" /><ProgressBarandroid:id="@+id/progressBar"style="?android:attr/progressBarStyleLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="8dp"android:visibility="@{loginViewModel.busy}" /></LinearLayout></ScrollView></layout>

The ProgressBar would be displayed to simulate the login feature.

将显示ProgressBar以模拟登录功能。

视图模型 (ViewModel)

The code for the LoginViewModel.java is given below:

下面给出了LoginViewModel.java的代码:

package com.journaldev.androidmvvmdatabindinglivedata;import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.ObservableField;
import android.os.Handler;
import android.support.annotation.NonNull;public class LoginViewModel extends BaseObservable {private String email;private String password;private int busy = 8;public final ObservableField<String> errorPassword = new ObservableField<>();public final ObservableField<String> errorEmail = new ObservableField<>();public LoginViewModel() {}private MutableLiveData<User> userMutableLiveData;LiveData<User> getUser() {if (userMutableLiveData == null) {userMutableLiveData = new MutableLiveData<>();}return userMutableLiveData;}@Bindable@NonNullpublic String getEmail() {return this.email;}public void setEmail(@NonNull String email) {this.email = email;notifyPropertyChanged(BR.email);}@Bindable@NonNullpublic String getPassword() {return this.password;}public void setPassword(@NonNull String password) {this.password = password;notifyPropertyChanged(BR.password);}@Bindablepublic int getBusy() {return this.busy;}public void setBusy(int busy) {this.busy = busy;notifyPropertyChanged(BR.busy);}public void onLoginClicked() {setBusy(0); //View.VISIBLEnew Handler().postDelayed(new Runnable() {@Overridepublic void run() {User user = new User(getEmail(), getPassword());if (!user.isEmailValid()) {errorEmail.set("Enter a valid email address");} else {errorEmail.set(null);}if (!user.isPasswordLengthGreaterThan5())errorPassword.set("Password Length should be greater than 5");else {errorPassword.set(null);}userMutableLiveData.setValue(user);setBusy(8); //8 == View.GONE}}, 5000);}
}

An ObservableField is an object wrapper to make it observable.
In the above code, we’ve encapsulated User inside a LiveData. Every time the user object is changed it will be observed in the MainActivity and the appropriate action would be taken.

ObservableField是使它可观察的对象包装。
在上面的代码中,我们将User封装在LiveData中。 每次更改用户对象时,都会在MainActivity中观察到该对象,并会采取适当的措施。

When the button is clicked, we set the ProgressBar to Visible. View.VISIBLE = 0.
View.GONE == 8

单击按钮后,我们将ProgressBar设置为Visible。 View.VISIBLE = 0
View.GONE == 8

After a delay of 5 seconds, the email and password are validated and the TextInputLayout bindables are updated.

延迟5秒后,将验证电子邮件和密码,并更新TextInputLayout可绑定对象。

ObservableField isn’t lifecycle aware.
ObservableField不支持生命周期。

The MainActivity.java class is given below:

MainActivity.java类如下所示:

package com.journaldev.androidmvvmdatabindinglivedata;import android.arch.lifecycle.Observer;
import android.databinding.DataBindingUtil;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;import com.journaldev.androidmvvmdatabindinglivedata.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);LoginViewModel loginViewModel = new LoginViewModel();binding.setLoginViewModel(loginViewModel);loginViewModel.getUser().observe(this, new Observer() {@Overridepublic void onChanged(@Nullable User user) {if (user.getEmail().length() > 0 || user.getPassword().length() > 0)Toast.makeText(getApplicationContext(), "email : " + user.getEmail() + " password " + user.getPassword(), Toast.LENGTH_SHORT).show();}});}
}

In the above code, the observe method looks for changes in the User object that was contained in the MutableLiveData. It displays a toast with the username and password.

在上面的代码中,observe方法在MutableLiveData中包含的User对象中查找更改。 它显示带有用户名和密码的吐司。

Now, let’s replace the ObservableField with LiveData completely.

现在,让我们用LiveData完全替换ObservableField。

将ObservableField重构为LiveData (Refactoring ObservableField to LiveData)

The code for the new LoginViewModel.java class is given below:

下面给出了新的LoginViewModel.java类的代码:

package com.journaldev.androidmvvmdatabindinglivedata;import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import android.os.Handler;public class LoginViewModel extends ViewModel {public MutableLiveData<String> errorPassword = new MutableLiveData<>();public MutableLiveData<String> errorEmail = new MutableLiveData<>();public MutableLiveData<String> email = new MutableLiveData<>();public MutableLiveData<String> password = new MutableLiveData<>();public MutableLiveData<Integer> busy;public MutableLiveData<Integer> getBusy() {if (busy == null) {busy = new MutableLiveData<>();busy.setValue(8);}return busy;}public LoginViewModel() {}private MutableLiveData<User> userMutableLiveData;LiveData<User> getUser() {if (userMutableLiveData == null) {userMutableLiveData = new MutableLiveData<>();}return userMutableLiveData;}public void onLoginClicked() {getBusy().setValue(0); //View.VISIBLEnew Handler().postDelayed(new Runnable() {@Overridepublic void run() {User user = new User(email.getValue(), password.getValue());if (!user.isEmailValid()) {errorEmail.setValue("Enter a valid email address");} else {errorEmail.setValue(null);}if (!user.isPasswordLengthGreaterThan5())errorPassword.setValue("Password Length should be greater than 5");else {errorPassword.setValue(null);}userMutableLiveData.setValue(user);busy.setValue(8); //8 == View.GONE}}, 3000);}
}

The above class now extends ViewModel since we no longer need BaseObservable.

上面的类现在扩展了ViewModel,因为我们不再需要BaseObservable

Now, we’ve changed the ObservableFields to MutableLiveData. Changes in the MutableLiveData would be automatically updated in the layout thanks to Data Binding.

现在,我们将ObservableFields更改为MutableLiveData。 MutableLiveData中的更改将由于数据绑定而在布局中自动更新。

Our MainActivity.java class is now updated to:

我们的MainActivity.java类现在更新为:

package com.journaldev.androidmvvmdatabindinglivedata;import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.databinding.DataBindingUtil;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;import com.journaldev.androidmvvmdatabindinglivedata.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);LoginViewModel loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);binding.setLoginViewModel(loginViewModel);binding.setLifecycleOwner(this);loginViewModel.getUser().observe(this, new Observer() {@Overridepublic void onChanged(@Nullable User user) {if (user.getEmail().length() > 0 || user.getPassword().length() > 0)Toast.makeText(getApplicationContext(), "email : " + user.getEmail() + " password " + user.getPassword(), Toast.LENGTH_SHORT).show();}});}
}

ViewModelProviders.of can be used to create ViewModel instance too as done above.
This method instantiates the ViewModel only once. Every subsequent call would reuse the instance.

如上所述, ViewModelProviders.of也可用于创建ViewModel实例。
此方法仅实例化ViewModel 一次 。 每个后续调用将重用实例。

The LifecycleOwner is an interface that our Activity can bind to.

LifecycleOwner是我们的Activity可以绑定的接口。

The output of the above application in action is given below:

上面应用程序的输出如下:

As you can see, the Toast message isn’t shown when the user leaves the application. Since the LiveData is lifecycle aware. When you open the application again, the toast would be displayed.

如您所见,当用户离开应用程序时,不会显示Toast消息。 由于LiveData是生命周期感知的。 当您再次打开应用程序时,将显示吐司。

This brings an end to this tutorial. You can download the project from the link below:

本教程到此结束。 您可以从下面的链接下载项目:

AndroidMVVMDataBindingLiveDataAndroidMVVMDataBindingLiveData
Github Project LinkGithub项目链接

翻译自: https://www.journaldev.com/22561/android-mvvm-livedata-data-binding

livedata mvvm

livedata mvvm_Android MVVM LiveData数据绑定相关推荐

  1. 【JetPack+Retrofit+Rxjava】获取Bing每日一图并显示ViewModel+LiveData+DataBinding+MVVM 补充笔记

    扉: 原文来自:Android官方架构组件ViewModel+LiveData+DataBinding架构属于自己的MVVM 很喜欢作者的思路,但是使用Kotlin需要配置的东西好多并且很多细节要重写 ...

  2. Windows Phone 7 MVVM模式数据绑定和传递参数

    数据绑定使用了ObservableCollection<T> 类来实现,ViewModel通过继承GalaSoft.MvvmLight.ViewModelBase类来实现,Command ...

  3. android mvvm 官方例子,详解Android的MVVM框架 - 数据绑定

    本教程是跟着 Data Binding Guide学习过程中得出的一些实践经验,同时修改了官方教程的一些错误,每一个知识点都有对应的源码,争取做到实践与理论相结合. Data Binding 解决了 ...

  4. Android之MVVM框架 - 数据绑定

    本教程是跟着 Data Binding Guide 学习过程中得出的一些实践经验,同时修改了官方教程的一些错误,每一个知识点都有对应的源码,争取做到实践与理论相结合. Data Binding 解决了 ...

  5. android mvvm_Android MVVM设计模式

    android mvvm In this tutorial, we'll be discussing and implementing the Android MVVM Architectural P ...

  6. MVVM双向数据绑定原理

    从视图到模型 通过change事件监听视图数据的变化,改变data中的值,实现模型改变,这个比较好理解 从模型到视图 重点我们需要知道模型改变会如何作用于视图 数据劫持 通过Object.define ...

  7. LiveData + ViewModel + Room (Google 官文)+Demo

    原文地址:lovestack.github.io/2017/11/13/- demo:github.com/lovestack/V- 本指南适用于那些过去构建应用程序有基础知识,现在想知道构建强大的生 ...

  8. LiveData使用和生命感知原理

    你知道LiveData是如何做到感知生命周期的吗? 前言 使用LiveData有以下优势 数据及时刷新:无论前台任务还是后台任务,只要当前页面处于活跃状态,就能马上刷新数据 不会因 Activity ...

  9. Google官方推荐 Flow 取代 LiveData

    1. LiveData有什么不足? 1.1 为什么引入LiveData? 要了解LiveData的不足,我们先了解下LiveData为什么被引入 LiveData 的历史要追溯到 2017 年.彼时, ...

最新文章

  1. 德式秘籍:产品总监最该学会的管理方法是什么?(一)
  2. scheduledexecutorservice 的使用_使用J.U.C实现定时任务
  3. 李彦宏被泼水背后,这些python AI发展的大事你都了解吗?
  4. php答题评分,Thinkphp 答题 评语
  5. 关于TaskStatus状态WaitingForChildrenToComplete 的疑问
  6. PAT天梯赛L3-004 肿瘤诊断
  7. 0-2岁的app开发人员必读,Android开发APP前的准备事项
  8. 【LeetCode之C#解法】 移动零、爬楼梯
  9. [html] 如何放大点击的区域?
  10. Linux 蓝牙读写,实战Linux Bluetooth编程(三) HCI层编程
  11. Docker入门之安装与卸载
  12. 以下是adb工具包最新Google官方版下载地址:
  13. 最全面的PS快捷键使用指南
  14. qt银行排队系统服务器代码,QT银行叫号排队系统
  15. AspNetPager 存储过程
  16. JAVA中级(五)response(1)基本介绍,代表响应的类,如何设置响应头,行,体
  17. python:select interpreter resulted in an error python.setINterpreter not found
  18. .net core 3.1 WebApi项目/Swagger支持二级目录
  19. 英语表达的收集类游戏
  20. 2020CTF笔记crypto部分

热门文章

  1. 数据库的Timeout
  2. 白领最低生存技能手册
  3. verilog状态机以及编码详解
  4. oracle误删除记录或者表的处理方法
  5. 【APIO2015】Bali Sculptures
  6. ADT版本不同导致的一个问题
  7. myeclipse堆栈溢出
  8. DirectX 9.0 SDK安装
  9. ubuntux学习日记
  10. 机器学习常用损失函数