Android---Jetpack之DataBinding

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

应用实现

 

\bullet 加载网络图片

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"对应,当然也可以写其它的内容)

 

\bullet 方法重载,加载本地图片

在 ImageViewBindingAdapter 里添加如下代码,并修改 xml 。我们可以看到,注解里的内容(localImage)与 app:localImage 对应。

    //TODO 加载本地图片
    @BindingAdapter("localImage")
    public static void setImage(ImageView image, Integer resId){
        image.setImageResource(resId);
    }

\bullet 多参数重载

多重参数可以实现参数的选择,先加载网络图片,如果失败,就加载本地图片。在 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);
        }
    }

 

双向绑定

\bullet 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 的优势

\bullet 不再需要 findViewById,项目更加简洁,可读性更高。

\bullet 布局文件可以包含简单的业务逻辑

完整Demo

提供上面所有应用的完整项目:

链接:https://pan.baidu.com/s/1xiK_h64IH1vnEzPOehh1ww 
提取码:5qzr

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别偷我的猪_09

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值