Jetpack入门:DataBinding

目录

一、DataBinding简介

设置 Data Binding

数据绑定表达式

双向绑定

二、例子

例1:DataBinding实现文本绑定和点击事件

 MainActivity :

CountStart :

Food: 

 OnClickListener :

 activity_main:

 build.gradle:

运行结果:

例二:二级界面的绑定

  activity_main:

sub_main: 

例三、双向绑定例子

 MainActivity:

 ViewModel :

 activity_main:

例四、使用@bindingAdapter注解加载图片

MainActivity : 

ImageBindingAdapter : 

activity_main: 

 注意事项:

三、总结

一、DataBinding简介

        DataBinding 是一种用于在安卓应用中实现简洁、高效的数据绑定的库。它使开发者能够以声明性的方式将 UI 组件与数据源进行绑定,从而自动更新界面上的数据,并简化了与 UI 相关的代码编写过程。

设置 Data Binding

要使用 Data Binding,需要进行以下设置:

  1. 在 app 模块的 build.gradle 文件中启用 Data Binding:

android {
    ...
    dataBinding {
        enabled = true
    }
}

    2. 在布局文件顶部添加 <layout> 标签来包裹布局内容:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 布局内容 -->
</layout>

3.在 Activity 或 Fragment 中获取绑定的实例:

// 在 Activity 中通过 setContentView 方法绑定布局
MyLayoutBinding binding = DataBindingUtil.setContentView(this, R.layout.my_layout);

// 在 Fragment 中通过 LayoutInflater 绑定布局
MyLayoutBinding binding = MyLayoutBinding.inflate(inflater, container, false);

数据绑定表达式

可以在布局文件中使用表达式语言来引用绑定的数据和执行操作,例如:

  • 引用变量或对象属性:

<TextView
    android:text="@{user.name}"
    ... />
  • 执行方法调用:
<Button
    android:onClick="@{onClickListener.onButtonClick()}"
    ... />
  • 使用条件语句和循环:
<TextView
    android:text="@{user.isAdult ? `Adult` : `Child`}"
    ... />

<LinearLayout
    android:visibility="@{user.isAdmin ? View.VISIBLE : View.GONE}"
    ... />

<RecyclerView
    app:itemList="@{list}"
    ... />

双向绑定

        双向绑定是一种数据绑定的概念,它使得视图(UI)和数据模型(Model)之间能够自动保持同步。当一个变量在视图中改变时,相关联的数据模型也会更新;反之,当数据模型的值发生变化时,视图也会相应地更新。

        DataBinding 还支持双向绑定,即将 UI 组件的变化反映到数据源中。可以通过 @= 符号实现双向绑定:

<EditText
    android:text="@={user.name}"
    ... />

二、例子

例1:DataBinding实现文本绑定和点击事件

 MainActivity :

package com.example.databinding2;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;


import android.os.Bundle;

import com.example.databinding2.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding mainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        // 利用DataBinding绑定UI文本
        Food food = new Food("麻辣烫", (float) 4);
        // 利用DataBinding实现点击事件
        mainBinding.setOnClickListener(new OnClickListener(this));
        mainBinding.setFood(food);
    }
}

CountStart :

package com.example.databinding2;

public class CountStart {
    public static String getStar(float star){
        return star +"星";
    }
}

Food: 

package com.example.databinding;

public class Food {
    public String name;
    public float star;
    public Food(String name,float star){
        this.name = name;
        this.star = star;
    }
}

 OnClickListener :

package com.example.databinding2;

import android.content.Context;
import android.view.View;
import android.widget.Toast;

public class OnClickListener {
    private Context mContext;
    public OnClickListener(Context context){
        mContext = context;
    }
    public void buttonOnClick(View view){
        Toast.makeText(mContext, "点击了提交!", Toast.LENGTH_SHORT).show();
    }

}

 activity_main:

<?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>
        <!-- 实现设置文本       -->
        <import type = "com.example.databinding2.CountStart"/>
        <variable
            name="Food"
            type="com.example.databinding2.Food" />
        <!-- 实现点击事件       -->
        <variable
            name="OnClickListener"
            type="com.example.databinding2.OnClickListener" />
    </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_begin="365dp" />

        <ImageView
            android:src="@drawable/img"
            android:id="@+id/imageView"
            android:layout_width="300dp"
            android:layout_height="300dp"
            app:layout_constraintBottom_toTopOf="@+id/guideline2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.497"
            tools:srcCompat="@tools:sample/avatars" />

        <RatingBar
            android:id="@+id/ratingBar"
            android:layout_width="244dp"
            android:layout_height="54dp"
            android:max="5"
            android:rating="@{Food.star}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintVertical_bias="0.079" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="129dp"
            android:layout_height="28dp"
            android:text="@{Food.name}"
            android:textSize="20sp"
            app:layout_constraintBottom_toTopOf="@+id/ratingBar"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.673"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.917" />

        <Button
            android:onClick="@{OnClickListener.buttonOnClick}"
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="160dp"
            android:text="提交"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{CountStart.getStar(Food.star)}"
            android:textSize="25sp"
            app:layout_constraintBottom_toTopOf="@+id/button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/ratingBar" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 build.gradle:


android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.databinding"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        dataBinding {
            enabled = true
        }
    }

运行结果:

例二:二级界面的绑定

  activity_main:

<?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>
        <!-- 实现设置文本       -->
        <import type = "com.example.databinding2.CountStart"/>
        <variable
            name="Food"
            type="com.example.databinding2.Food" />
        <!-- 实现点击事件       -->
        <variable
            name="OnClickListener"
            type="com.example.databinding2.OnClickListener" />
    </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_begin="365dp" />

        <ImageView
            android:src="@drawable/img"
            android:id="@+id/imageView"
            android:layout_width="300dp"
            android:layout_height="300dp"
            app:layout_constraintBottom_toTopOf="@+id/guideline2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.497"
            tools:srcCompat="@tools:sample/avatars" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="129dp"
            android:layout_height="28dp"
            android:text="@{Food.name}"
            android:textSize="20sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.673"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <include
            app:Food="@{Food}"
            app:OnClickListener="@{OnClickListener}"
            layout="@layout/sub_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.497"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintVertical_bias="0.253" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

sub_main: 

<?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="Food"
            type="com.example.databinding2.Food" />
        <!-- 实现点击事件       -->
        <variable
            name="OnClickListener"
            type="com.example.databinding2.OnClickListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RatingBar
            android:id="@+id/ratingBar2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:rating="@{Food.star}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.438"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.065" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="@{Food.name}"
            android:textSize="25sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.449"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/ratingBar2" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="提交"
            android:onClick="@{OnClickListener.buttonOnClick}"
            android:textSize="20sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.463"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView3" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 其他代码和运行效果跟例一一样。

例三、双向绑定例子

 MainActivity:

public class MainActivity extends AppCompatActivity {
    private ViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 使用DataBindingUtil进行绑定
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        // 初始化ViewModel
        viewModel = new ViewModel();

        // 设置ViewModel到绑定对象中
        binding.setViewModel(viewModel);
    }
}

 ViewModel :

public class ViewModel extends BaseObservable {
    private String inputText;

    @Bindable
    public String getInputText() {
        return inputText;
    }

    public void setInputText(String inputText) {
        this.inputText = inputText;
        notifyPropertyChanged(BR.inputText);
    }
}

 activity_main:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="com.example.ViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={viewModel.inputText}" />

        <!-- 其他视图 -->

    </LinearLayout>
</layout>

例四、使用@bindingAdapter注解加载图片

         @BindingAdapter 注解是用于在 DataBinding 中绑定自定义属性和方法的注解。通过 @BindingAdapter 注解,我们可以定义一个静态方法,在该方法中实现各种自定义的数据绑定逻辑。 

MainActivity : 

package com.example.databinding32;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

import android.os.Bundle;

import com.example.databinding32.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding mainBinding =DataBindingUtil.setContentView(this,R.layout.activity_main);
        mainBinding.setNetworkImage("https://img-home.csdnimg.cn/images/20201124032511.png");
//        mainBinding.setLocalImage(R.drawable.ic_launcher_background);
    }
}

ImageBindingAdapter : 

package com.example.databinding32;

import android.text.TextUtils;
import android.widget.ImageView;

import androidx.databinding.BindingAdapter;

import com.squareup.picasso.Picasso;

public class ImageBindingAdapter {
    // 加载网络图片
    @BindingAdapter("image")
    public static void setImage(ImageView image,String url){
        if (!TextUtils.isEmpty(url)){
            Picasso.get()
                    .load(url)
                    .placeholder(R.drawable.ic_launcher_background)
                    .into(image);
        }else {
            image.setImageResource(R.drawable.ic_launcher_background);
        }

    }
    // 加载本地图片
    @BindingAdapter("image")
    public static void setImage(ImageView image,int resId){
        image.setBackgroundResource(resId);
    }
    // 如果没有url就加载本地图片
    @BindingAdapter(value = {"image","defaultImageResources"},requireAll = false)
    public static void setImage(ImageView image,String url,int resId){
        if (!TextUtils.isEmpty(url)){
            Picasso.get()
                    .load(url)
                    .placeholder(R.drawable.ic_launcher_background)
                    .into(image);
        }else {
            image.setBackgroundResource(resId);
        }
    }
}

activity_main: 

<?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="int" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="250dp"
            android:layout_height="250dp"
            app:image="@{networkImage}"
            app:defaultImageResources="@{localImage}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:srcCompat="@tools:sample/avatars" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 注意事项:

使用 @BindingAdapter 注解时,需要注意以下几点:

  1. 注解位置:@BindingAdapter 注解可以应用于任何静态方法上。

  2. 方法参数:@BindingAdapter 方法通常具有两个参数:视图对象(例如 TextViewImageView)和要绑定的属性值(例如字符串、图像资源等)。方法可以有任意多个参数,但前两个参数必须是视图对象和对应的属性值。

  3. 方法命名:为了与属性关联,方法名称通常以 "set" 开头,后面跟着要绑定的属性的名称。例如,如果要绑定 imageUrl 属性,方法可以被命名为 setImageUrl(ImageView view, String url)

  4. 参数注解:当 @BindingAdapter 方法有多个参数时,可以使用其他注解来标识不同的参数。例如,可以使用 @BindingAdapter({"imageUrl", "placeholder"}) 来指定方法的第一个参数对应的是 imageUrl 属性,第二个参数对应的是 placeholder 属性。

  5. 属性名称:在布局文件中,可以使用 app:属性名称 的方式来设置自定义的绑定属性。例如,app:imageUrl="@{viewModel.imageUrl}"

三、总结

        使用 DataBinding 的主要意义在于简化安卓应用中的数据绑定和 UI 更新过程,提高开发效率和代码可读性。以下是使用 DataBinding 的一些重要意义:

1. 简化代码结构:通过 DataBinding,可以将布局文件和数据源直接绑定,从而减少了编写繁琐的 findViewById() 和手动设置数据的代码。这样可以使代码更加简洁、清晰,并且减少了因为手动更新 UI 导致的错误。

2. 减少空指针异常:DataBinding 使用空安全的表达式语言,可以避免由于数据为空而导致的空指针异常。通过在表达式中处理 null 值,可以确保安全地访问和操作数据。

3. 提高性能:Data Binding 可以实现数据与界面的实时绑定,只有当数据发生变化时才会触发 UI 的更新,相比传统的手动更新方式,能够有效地降低不必要的 UI 刷新,提高应用的性能和响应速度。

4. 支持双向绑定:DataBinding 支持双向绑定,即可以将用户对 UI 的修改反映到数据源中。这样可以轻松地实现表单输入、状态切换等功能,无需额外的回调或监听器。

5. 增强代码可读性:使用 DataBinding,可以将 UI 相关的代码和业务逻辑分离,使代码结构更加清晰,提高了代码的可读性和维护性。开发者可以专注于处理数据和逻辑层面,而不需要直接操作界面元素。

        总之,使用 DataBinding 可以简化数据绑定过程、提高性能和代码可读性,减少错误,并提供了更灵活的数据绑定和双向绑定功能。它是一种强大的工具,可以提升安卓应用的开发效率和用户体验。

未完待续。。。。。。

猜你喜欢

转载自blog.csdn.net/A125679880/article/details/131756222