前提:导入所有依赖,开启DataBinding

app的build.gradle

android {
defaultConfig {
。。。
dataBinding {
enabled true
}
}
}
dependencies {
def lifecycle_version = "2.1.0" // ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx
// alternatively - just LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
// AndroidX libraries use this lightweight import for Lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // For Kotlin use kapt instead of annotationProcessor
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
}

ViewModel

1.定义Model类集成androidx.lifecycle.ViewModel,并编写数据操作逻辑

class MyViewModel : ViewModel() {
private var mNumber = MutableLiveData<Int>(0) fun getNumber() = mNumber
fun setNumber(number: Int) {
mNumber.value = number
}
}
// 使用MutableLiveData类包装数据,支持livedata
//为了在ViewModel中使用Context,可以继承AndroidViewModel

2.Activity类中直接调用Model类的方法来操作数据

ViewModel的另一个用途:在Fragment之间共享数据

以下示例了来自jetpack官方文档:

/*
在 Fragment 之间共享数据
Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的情况。想象一下主从 Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。
可以使用 ViewModel 对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享 ViewModel 来处理此类通信,如以下示例代码所示:
*/
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
} class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this)[SharedViewModel::class.java]
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
} class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this)[SharedViewModel::class.java]
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
/*
请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 ViewModelProvider 时,它们会收到相同的 SharedViewModel 实例(其范围限定为该 Activity)。
此方法具有以下优势:
1)Activity 不需要执行任何操作,也不需要对此通信有任何了解。
2)除了 SharedViewModel 约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。
3)每个 Fragment 都有自己的生命周期,而不受另一个 Fragment 的生命周期的影响。如果一个 Fragment 替换另一个 Fragment,界面将继续工作而没有任何问题。
*/

LiveData

1.注册观察器

mViewModel.getNumber().observe(
this,
Observer { it->
mText1.text = it.toString()
mText2.text = it.toString()
}
)
// Model类中必须使用包装器才可以进行监听
// it参数类型为int,即原本数据类型而非包装器

DataBinding

1.将Activity与xml进行连接

onCreate中,使用
val binding = DataBindingUtil.setContentView(this, R.layout.activity_main) as ActivityMainBinding
代替
setContentView(R.layout.activity_main)

2.xml文件中插入数据类

使用包裹根布局,并插入标签:

<layout>
<data>
<variable //该变量在本xml文件中使用
name="data" //变量名
type="com.example.test.MyViewModel" /> //变量类型
</data>
<ConstraintLayout>
。。。
UI
。。。
<TextView
android:text="@{String.valueOf(data.mNumber)}">
<Button
android:onClick="@{()->data.setNumber(data.mNumber + 1)}">
<ConstraintLayout>
</layout>

3.将数据绑定至xml中

binding.data = mViewModel        //绑定数据
binding.lifecycleOwner = this //绑定生命周期

改变配置、内存回收等情况下的数据保持

1.使用saveInstanceState
在onSaveInstanceState(Bundle)和onRestoreInstanceState(Bundle)中进行操作
2.使用SharePreference
3.使用ViewModel持有一个SavedStateHandle对象,利用该对象保存数据
class MyViewModel(var handle : SavedStateHandle) : ViewModel() {
init {
if (!handle.contains("NUMBER"))
handle.set("NUMBER", 0)
}
fun getNumber() : LiveData<Int> = handle.getLiveData("NUMBER")
fun add() {
val number : Int = handle.get("NUMBER")!!
handle.set("NUMBER", number + 1)
}
}

经过改造后的Activity

//Activity
package com.example.test import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProviders
import com.example.test.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val mViewModel = ViewModelProviders.of(this)[MyViewModel::class.java]
/*
最新版本用以下方法创建ViewModel:
val mViewModel = ViewModelProvider(this).get(MyViewModel::class)
*/
val binding = DataBindingUtil.setContentView(this, R.layout.activity_main) as ActivityMainBinding binding.data = mViewModel
binding.lifecycleOwner = this //使用ViewModel操作数据
}
}
//Model类
package com.example.test import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel class MyViewModel : ViewModel() {
private var mNumber = MutableLiveData<Int>(0) fun getNumber() = mNumber fun setNumber(number: Int) {
mNumber.value = number
}
}
//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"> <data> <variable
name="data"
type="com.example.test.MyViewModel" />
</data> <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="@{String.valueOf(data.number)}"
android:freezesText="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" /> <Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="+1"
android:onClick="@{()->data.setNumber(data.number + 1)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" /> <Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="+2"
android:onClick="@{()->data.setNumber(data.number + 2)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button1" /> <TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="@{String.valueOf(data.number)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button2" /> </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Android Jetpack基本架构之ViewModel+LiveData+DataBinding入门的更多相关文章

  1. 【Android Jetpack高手日志】DataBinding 从入门到精通

    前言 DataBinding 数据绑定库是 Android Jetpack 的一部分,借助该库可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源.我个人觉得,使用 DataBin ...

  2. Android Jetpack 架构组件最佳实践之“网抑云”APP

    背景 近几年,Android 相关的新技术层出不穷.往往这个技术还没学完,下一个新技术又出来了.很多人都是一脸黑人问号? 不少开发者甚至开始哀嚎:"求求你们别再创造新技术了,我们学不动了!& ...

  3. 【Android】ViewModel+LiveData:更加直接地控制视图的方式

    目录 LiveData 前言 使用ViewModel+LiveData LiveData 前言   ViewModel通过将UI data保存在ViewModel类实例的内部,从而大大地将MVC中的 ...

  4. 带你了解Android Jetpack

    1.Jetpack主要特性有以下三点: 1.加速开发组件可单独使用,也可以协同工作,当使用kotlin语言特性时,可以提高效率. 2.消除样板代码Android Jetpack可管理繁琐的Activi ...

  5. Android Jetpack组件

    带你领略Android Jetpack组件的魅力 Android新框架jetpack的内容讲解:Room.WorkManager.LifeCycles.LiveData.ViewModel.DataB ...

  6. 安卓基础(LiveData DataBinding)

    昨天因为有点事情,没有及时发表博客,昨天学习了LiveData和DataBinding,LiveData属于jetpack中的框架里面的,DataBinding可以进行数据绑定. 我分别利用这两部分知 ...

  7. 乘风破浪,遇见Android Jetpack之Compose声明式UI开发工具包,逐渐大一统的原生UI绘制体系

    什么是Android Jetpack https://developer.android.com/jetpack Android Jetpack是一个由多个库组成的套件,可帮助开发者遵循最佳做法.减少 ...

  8. 学习Android Jetpack? 入门教程和进阶实战这里全都有!

    前言 2018年谷歌I/O,Jetpack横空出世,官方介绍如下: Jetpack 是一套库.工具和指南,可帮助开发者更轻松地编写优质应用.这些组件可帮助您遵循最佳做法.让您摆脱编写样板代码的工作并简 ...

  9. Android Jetpack 组建介绍(一)——Lifecycler

    转自带你领略Android Jetpack组件的魅力 Android Jetpack 对于任何一个产品来说,我们开发中都会面对哪些问题?如:产品交互.用户体验.代码结构.数据获取.数据存储.网络优化. ...

随机推荐

  1. 前端知识点--CSS overflow 属性

    问题:如何加滚动条? 给div 设置css 样式overflow:scroll div { width:150px; height:150px; overflow:scroll; } -------- ...

  2. 基于ifix组态软件研究控制按钮权限

    背景: 在前阵子做基于ifix生成电力监控平台时,遇到业主提出的一个需求.关于如何在控制弹窗中,点击相应的合分闸按钮时,优先弹出登录界面,当输入相应的有权限用户名和密码后,才能操作这一要求.后实现如下 ...

  3. videojs文档翻译Guides-components

    components Components Video.js播放器的架构围绕组件. Player类和所有表示播放器控件和其他UI元素的类都继承自Component类. 这种架构使得可以轻松地以反映DO ...

  4. Go语言基础知识总结(持续中)

    Go基础知识总结 变量声明 Go语言中的变量需要声明以后才可以使用(需要提前定义变量)并且声明后必须使用(不适用会报错) 标准声明 var 变量名 变量类型 example: var name str ...

  5. 【GCC编译器】将GIMPLE序列划分成基本块(Basic block),并构造控制流图

    1. 首先介绍测试用例,这是一个简单的if-then-else结构,输入为 int 类型的单变量,输出为 int 类型的结果.如果条件 a < 1 成立,则将输入直接返回:如果条件不成立,则返回 ...

  6. ; 按快捷键`(即波浪号~所在的键盘按键)立即打开随身U盘中的办公专用文件夹

    ; 按快捷键`(即波浪号~所在的键盘按键)立即打开随身U盘中的办公专用文件夹; WorkFolderHotkey.ahk;; http://www.autoahk.com/; https://www. ...

  7. 最高级的AutoHotkey重试源代码结构20191221.docx

    ;; 最高级的AutoHotkey重试源代码结构20191221.docx;; 在编写AutoHotkey脚本时经常要用到重试,; 单击控件无效时需要重新再单击,; 发送模拟按键无效时需要重新发送.; ...

  8. noip模拟测试16

    这次考试,难度还是不小的,先说一下考试过程,首先看一遍题,觉得开题顺序1 3 2, 然后我就先打了第一题,我当时可能是受到之前做题的限制了,觉得他只能每次走一 格,也就是一个单位长度,但是实际上,他甚 ...

  9. js原始数据类型有哪些,引用数据类型有哪些

    js的数据类型划分方式为 原始数据类型和 引用数据类型 栈: 原始数据类型(Undefined,Null,Boolean,Number.String) 堆: 引用数据类型(对象.数组.函数) 两种类型 ...

  10. C++ 二进制文件 读 写文件

    1 #include <iostream> 2 #include <string> 3 #include<fstream> 4 using namespace st ...