DataBinding 的意义
让布局文件承担了部分原本属于页面的工作,使页面与布局耦合度进一步降低。
DataBinding 的应用
使用 dataBinding 需要在 gradle 里添加如下代码
dataBinding{
enabled = true
}
应用实现
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">
<data>
<!-- 使用一个类对象 -->
<variable
name="Idol"
type="com.example.databinding.Idol" />
<variable
name="eventHandle"
type="com.example.databinding.EventHandlerListener" />
<!-- 引入一个类 -->
<import type="com.example.databinding.StarUtils"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/imageView"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/lanyangyang"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.56"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="姓名"
android:text="@{Idol.name}"
android:textSize="24sp"
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="@+id/guideline3"
app:layout_constraintVertical_bias="0.184" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
tools:text="五星"
android:text="@{StarUtils.getStar(Idol.star)}"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="72dp"
android:text="喜欢"
android:onClick="@{eventHandle.buttonOnClick}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
注意:使用 databinding 是要修改 xml 布局的。可以看到,上面的布局整个是包裹住 <layout></layout> 里面的,并且里面还要 <data></data>。当我们在 gradle 里引入了 dataBinding 后,Android studio 也给我们提供了一键生成<layout></layout> 的方法,如下图:
通过上图3不操作后,就能只能生成 <layout></layout>。下面解释一下<data></data> 以及里面的<variable>变量
当我在 xml 里有了 Idol 对象,就可以在xml里调用 Idol 里的成员变量方法等。
直接取 Idol 里 name 变量赋值给 text。
Idol.java
package com.example.databinding;
public class Idol {
public String name;
public int star;
public Idol(String name, int star) {
this.name = name;
this.star = star;
}
}
starUtils.java
package com.example.databinding;
public class StarUtils {
public static String getStar(int star){
switch (star) {
case 1:
return "一星";
case 2:
return "二星";
case 3:
return "三";
case 4:
return "四星";
case 5:
return "五星";
}
return "";
}
}
EventHandlerListener.java
package com.example.databinding;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import com.google.android.material.tabs.TabItem;
public class EventHandlerListener {
private Context context;
public EventHandlerListener(Context context) {
this.context = context;
}
public void buttonOnClick(View view){
Toast.makeText(context, "超可爱", Toast.LENGTH_SHORT).show();
}
}
MainActivity.java
package com.example.databinding;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.example.databinding.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Idol idol = new Idol("懒洋洋", 4);
//TODO setIdol 是 activity_main 里面 variable 下的 Idol, 给它赋一个 idol 对象,
// 那么就可以在 xml 里操作 Idol 里面的成员变量合方法了
binding.setIdol(idol);
binding.setEventHandle(new EventHandlerListener(this));
}
}
因为我们在 <data></data> 的 <variable/> 里有关 name="Idol" 和 name="eventHandle" 两个,所以就可以直接在 MainActivity 里 setIdol(new Idol("懒洋洋", 4)) 和 setEventHandle(new ....)。
> 里有
二级页面的绑定
<include>标签引用二级页面
应用实现
sub.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="Idol"
type="com.example.databinding2.Idol" />
<!-- 引入一个类 -->
<import type="com.example.databinding2.StarUtils"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
tools:text="懒洋洋"
android:text="@{Idol.name}"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
tools:text="五星"
android:text="@{StarUtils.getStar(Idol.star)}"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
使用二级页面的注意点就是,如何将 idol 对象在 activity_main.xml 里传入到二级页面里(sub.xml)
main_activity.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="Idol"
type="com.example.databinding2.Idol" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<ImageView
android:id="@+id/imageView"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/lanyangyang"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.56"
tools:srcCompat="@tools:sample/avatars" />
<include
layout="@layout/sub"
app:Idol="@{Idol}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
注意:app:Idol 的这个 Idol 要与 sub.xml 里的 name="Idol" 要一样。
自定义 BindingAdapter
应用实现
加载网络图片
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">
<data>
<variable
name="netWorkImage"
type="String" />
<variable
name="localImage"
type="Integer" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
app:image="@{netWorkImage}"
android:layout_width="300dp"
android:layout_height="300dp"
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"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ImageViewBindingAdapter.java
package com.example.databinding3;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
import com.squareup.picasso.Picasso;
public class ImageViewBindingAdapter {
// TODO 下面的三个方法名相同,但参数不同 ---> 方法重载
//TODO 加载网络图片
@BindingAdapter("image")
public static void setImage(ImageView image, String Url){
if (!TextUtils.isEmpty(Url)) {
Picasso.get()
.load(Url)
.into(image);
}else {
image.setBackgroundColor(Color.GRAY);
}
}
}
MainActivity.java
package com.example.databinding3;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import com.example.databinding3.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setNetWorkImage("https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0613%2Fcdf32afaj00rdepyy001vc000zk00geg.jpg&thumbnail=660x2147483647&quality=80&type=jpg");
//binding.setLocalImage(R.drawable.yan);
}
}
我们使用 @BindingAdapter 注解,然后 就会将 xml 里 networkImage 的内容和 这个 ImageView 一起出传到有@BindingAdapter 注解的这个方法里(根据"iamge"对应,当然也可以写其它的内容)
方法重载,加载本地图片
在 ImageViewBindingAdapter 里添加如下代码,并修改 xml 。我们可以看到,注解里的内容(localImage)与 app:localImage 对应。
//TODO 加载本地图片
@BindingAdapter("localImage")
public static void setImage(ImageView image, Integer resId){
image.setImageResource(resId);
}
多参数重载
多重参数可以实现参数的选择,先加载网络图片,如果失败,就加载本地图片。在 ImageViewBindingAdapter 里添加如下代码,并修改 xml 。
//TODO 参数可选,先加载网络图片,如果 Url 为空,再加载本地图片
@BindingAdapter(value = {"image", "defaultImage"}, requireAll = false)
public static void setImage(ImageView image, String Url, Integer resId){
if (!TextUtils.isEmpty(Url)) {
Picasso.get()
.load(Url)
.into(image);
}else {
image.setImageResource(resId);
}
}
双向绑定
BaseObservable 与 ObservableField
应用实现
1. 使用 BaseObservable
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">
<data>
<variable
name="userViewModel"
type="com.example.databinding4.UserViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="@={userViewModel.userName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
User.java
package com.example.databinding4;
public class User {
public String userName;
public User(String userName) {
this.userName = userName;
}
}
UserViewModel.java 继承 BaseObservable
package com.example.databinding4;
import android.util.Log;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class UserViewModel extends BaseObservable {
private final User user;
public UserViewModel(){
this.user = new User("HL");
}
/**
* TODO 当 user.userName 的内容发生改变时(后台操作),也会同步到界面(EditText)
*/
@Bindable
public String getUserName(){
return user.userName;
}
/**
*TODO 当 EditText 的内容发生改变时(界面操作),也会同步到 user.userName
* @param userName
*/
public void setUserName(String userName){
if (userName != null && !user.userName.equals(userName)) {
user.userName = userName;
Log.d("HL", "setUserName: " + userName);
notifyPropertyChanged(BR.userName);
}
}
MainActivity.java
package com.example.databinding4;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import android.os.Bundle;
import com.example.databinding4.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUserViewModel(new UserViewModel());
}
}
2. 使用 ObservableField
修改 UserViewModel 内容如下,不用再继承 BaseObservable。这种方法代码更简单
package com.example.databinding5;
import android.util.Log;
import androidx.databinding.ObservableField;
public class UserViewModel{
// TODO 使用 ObservableField
private ObservableField<User> userObservableField;
public UserViewModel(){
userObservableField = new ObservableField<>();
User user = new User("HL");
userObservableField.set(user);
}
public String getUserName(){
return userObservableField.get().userName;
}
public void setUserName(String userName){
Log.d("HL", "userObservableField: " + userName);
userObservableField.get().userName = userName;
}
}
RecyclerView 的绑定
MyRecyclerViewAdapter extends RecyclerView.Adapter。在 onCreateViewHolder 里拿到 item.xml。在 onBindViewHolder 里给每个 item 绑定 idol。其它代码的写法与常规使用 RecyclerView 一样。
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemBinding inflate = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);
return new MyViewHolder(inflate);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Idol idol = idols.get(position);
holder.itemBinding.setIdol(idol); //TODO 把 idol 对象设置到 item.xml 里面了
}
DataBinding+ViewModel+LiveData
引用实现
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">
<data>
<variable
name="viewModel"
type="com.example.databinding7.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.050615594" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15458277" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="310dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="225dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="390dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="482dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="556dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="206dp" />
<TextView
android:id="@+id/a_team"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TeamA"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline2" />
<TextView
android:id="@+id/b_team"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TeamB"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline2" />
<TextView
android:id="@+id/a_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(viewModel.getaTeamScore)}"
android:textColor="@android:color/holo_red_light"
android:textSize="44sp"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
<TextView
android:id="@+id/b_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(viewModel.getbTeamScore)}"
android:textColor="@color/teal_200"
android:textSize="44sp"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
<Button
android:id="@+id/a_add1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+1"
android:onClick="@{()->viewModel.aTeamAdd(1)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<Button
android:id="@+id/b_add1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+1"
android:onClick="@{()->viewModel.bTeamAdd(1)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<Button
android:id="@+id/a_add2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+2"
android:onClick="@{()->viewModel.aTeamAdd(2)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<Button
android:id="@+id/b_add2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+2"
android:onClick="@{()->viewModel.bTeamAdd(2)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<Button
android:id="@+id/a_add3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+3"
android:onClick="@{()->viewModel.aTeamAdd(3)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline7"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline6"
app:layout_constraintVertical_bias="0.454" />
<Button
android:id="@+id/b_add3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+3"
android:onClick="@{()->viewModel.bTeamAdd(3)}"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/guideline7"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline6" />
<ImageView
android:id="@+id/clear"
android:layout_width="50dp"
android:layout_height="50dp"
android:onClick="@{()->viewModel.undo()}"
app:layout_constraintBottom_toTopOf="@+id/guideline8"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline7"
app:srcCompat="@drawable/clear" />
<ImageView
android:id="@+id/resent"
android:layout_width="50dp"
android:layout_height="50dp"
android:onClick="@{()->viewModel.resentScore()}"
app:layout_constraintBottom_toTopOf="@+id/guideline8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline9"
app:layout_constraintTop_toTopOf="@+id/guideline7"
app:srcCompat="@drawable/resent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MyViewModel.java
package com.example.databinding7;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> aTeamScore;
private MutableLiveData<Integer> bTeamScore;
private Integer aLast;
private Integer bLast;
public MutableLiveData<Integer> getaTeamScore() {
if (aTeamScore == null) {
aTeamScore = new MutableLiveData<>();
aTeamScore.setValue(0);
}
return aTeamScore;
}
public MutableLiveData<Integer> getbTeamScore() {
if (bTeamScore == null) {
bTeamScore = new MutableLiveData<>();
bTeamScore.setValue(0);
}
return bTeamScore;
}
/**
* A 队得分
* @param score 所得的分数(1/2/3)
*/
public void aTeamAdd(int score){
recordLastScore();
aTeamScore.setValue(aTeamScore.getValue() + score);
}
/**
* B 队得分
* @param score 所得的分数(1/2/3)
*/
public void bTeamAdd(int score){
recordLastScore();
bTeamScore.setValue(bTeamScore.getValue() + score);
}
/**
* 返回上一次的得分
*/
public void undo(){
aTeamScore.setValue(aLast);
bTeamScore.setValue(bLast);
}
/**
* 记录上一次的得分
*/
public void recordLastScore(){
this.aLast = aTeamScore.getValue();
this.bLast = bTeamScore.getValue();
}
/**
* 分数重置为 0
*/
public void resentScore(){
aTeamScore.setValue(0);
bTeamScore.setValue(0);
}
}
MainActivity.java
package com.example.databinding7;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import com.example.databinding7.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MyViewModel myViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);
binding.setViewModel(myViewModel);
binding.setLifecycleOwner(this);
}
}
DataBinding 的优势
不再需要 findViewById,项目更加简洁,可读性更高。
布局文件可以包含简单的业务逻辑
完整Demo
提供上面所有应用的完整项目:
链接:https://pan.baidu.com/s/1xiK_h64IH1vnEzPOehh1ww
提取码:5qzr