env : android studio 3.5, Android Q
data : 2019/10/12
author : lrcoder
使用Jetpack开发工具的优势
- 代码结构逻辑更加模块化
- 代码向后兼容, 减少系统崩溃和内存泄漏的问题
- 方便代码管理,Jetpack可以管理(后台任务、导航栏、生命周期等)
- 提高代码运行效率
1.ViewModel
ViewModel 可以用作储存界面数据,取代
Bundle savedInstanceState
存储数据。ViewModel就是一个存储着我们界面数据的类,界面数据的设定全部来自自定义的ViewModel。
首先,我们需要对某一个界面(例如:MainActivity)设定一个ViewModel(Demo中使用的是MyViewModel
继承自 ViewModel
)
- 我需要对每一个界面定义一个专属的ViewModel,这样易于维护,且代码较为美观;
- ViewModel的包为
androidx.lifecycle.ViewModel
- MainActivity 需要引用包
androidx.lifecycle.ViewModelProviders
,注意ViewModelProviders
后需要有"s",使用时需要添加依赖implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
import androidx.lifecycle.ViewModel;
class MyViewModel extends ViewModel {
private int textViewContent = 0;
int getTextViewContent() {
return textViewContent;
}
void setTextViewContent(int textViewContent) {
this.textViewContent = textViewContent;
}
}
接着我们在MainActivity中声明和使用我们针对于该Activity创建的ViewModel
//获取ViewModel类的对象
MyViewModel myViewModel;
//在onCreate()方法中获取ViewModel的具体内容
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
也就是说以后我们在给控件赋值时只需要获取ViewModel实例中的数值即可,修改数值也是直接修改ViewModel中对应的数值
//修改数值为当前 textViewContent + 1
myViewModel.setTextViewContent(myViewModel.getTextViewContent() + 1);
//给控件赋值为 textViewContent + 1
textView.setText(String.valueOf(myViewModel.getTextViewContent()));
//为了保证每次界面销毁重启后,都可以保存之前的值,我们需要在onCreate()中,给控件赋值为 textViewContent
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
textView = findViewById(R.id.text);
textView.setText(String.valueOf(myViewModel.getTextViewContent()));
}
2、LiveData
LiveData的作用是让底层数据更新时,自动更新界面控件视图,减少手动
setText()
同样作为视图数据管理的一个类,LiveData写在ViewModel类中。将被管理的值放于MutableLiveData<>
容器中
- 注意
MyViewModel类
和MyViewModel类
的声明需要是public
- 注意拓展
MutableLiveData<>
容器中可以存放多种数据类型List<>
、String
等等 - 需要提供修改参数的方法
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> textViewContent;
public MyViewModel(){
textViewContent = new MutableLiveData<>();
textViewContent.setValue(0);
}
MutableLiveData<Integer> getTextViewContent() {
if (textViewContent == null) {
textViewContent = new MutableLiveData<>();
textViewContent.setValue(0);
}
return textViewContent;
}
void addTextViewContent(int n) {
textViewContent.setValue(textViewContent.getValue() + n);
}
}
接着在MainActivity中声明控件、声明ViewModel管理类、绑定ViewModel管理类、设置LiveData观察者
- 点击事件由直接设置控件值变为设置
ViewModel
对应属性值 - 控件属性值通过观察者的
onChanged()
方法设置 - 代码和视图分离,代码结构更加清晰
public class MainActivity extends AppCompatActivity {
//声明控件
MyViewModel myViewModel;
Button button1, button2;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定视图
setContentView(R.layout.activity_main);
//找到控件
textView = findViewById(R.id.text1);
button1 = findViewById(R.id.button2);
button2 = findViewById(R.id.button);
//绑定ViewModel管理类
myViewModel = ViewModelProviders.of(this).get(MyViewModelTest.class);
//设置ViewModel观察者
myViewModel.getTextViewContent().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
textView.setText(String.valueOf(integer));
}
});
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myViewModel.addTextViewContent(1);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myViewModel.addTextViewContent(2);
}
});
}
}
3、Data Binding
将数据和View绑定,减少声明控件、减少找到控件的过程
data Binding的使用和声明涉及到build.gradle
、Java
、xml
三个部分。
首先在build.gradle
中打开dataBinding
的开关
dataBinding{
enabled=true
}
接下来完成Java
部分的ViewModel
的创建
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> textViewContent;
public MyViewModel(){
textViewContent = new MutableLiveData<>();
textViewContent.setValue(0);
}
public MutableLiveData<Integer> getTextViewContent() {
if (textViewContent == null) {
textViewContent = new MutableLiveData<>();
textViewContent.setValue(0);
}
return textViewContent;
}
public void addTextViewContent(int n) {
textViewContent.setValue(textViewContent.getValue() + n);
}
}
在MainActivity
中进行控件的绑定、声明
由于在build.gradle
中打开了dataBinding
的开关,那么我们可以在MainActivity
中获取一个类ActivityMainBinding
,这个是动态生成的,名称的组合为res
-layout
-activity_main.xml
中.xml
文件的名字加上Binding
。
-
binding.setMyViewModel(myViewModel)
中的MyViewModel
,需要和xml
文件中的name
属性相对应
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
//声明绑定的xml文件
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定xml视图文件
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
//绑定ViewModel管理类
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
//声明属性(该属性与xml文件中设置的数据name相对应)
binding.setMyViewModel(myViewModel);
//声明视图生命周期拥有者
binding.setLifecycleOwner(this);
}
}
最后修改xml
文件内容
- 使用
layout
标签包裹整个xml
文件 - 添加
data
标签 - 在
data
标签中添加variable
标签来规定使用的数据名、绑定的ViewModel
- 在
xml
文件中设置text
的属性内容- 变量的使用格式为
@{name.变量名(可能需要在其中做一些类型转换)}
- 函数的使用格式为
@{()->name.函数(包括参数)}
- 变量的使用格式为
<?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="myViewModel"
type="com.code.databingdingdemo.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:text="@{String.valueOf(myViewModel.textViewContent)}"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.479"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.341" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="356dp"
android:onClick="@{()->myViewModel.addTextViewContent(1)}"
android:text="+1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.116" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>