Android数据绑定高级概念

时间:2020-02-23 14:28:52  来源:igfitidea点击:

在本教程中,我们将研究应用程序中数据绑定的其他一些棘手用法。
为了更好地理解本教程,请查看Android数据绑定教程。

Android数据绑定概述

在上一教程中,我们研究了数据绑定方法如何消除了使用findViewById连接应用程序代码中的UI视图对象的需求。
与findViewById相比,数据绑定的另一个优点是它可以提高应用程序的性能。
使用findViewById要求我们在每次调用视图时都在整个层次结构中进行查找。
因此,它需要为每个子视图单次遍历整个视图层次结构。
另一方面,数据绑定仅使用一次传递,并存储每个子视图布局的所有字段名称。
由于我们已经在第一遍中找到了所有视图,因此无需第二遍。

Android数据绑定概述

数据绑定有很多要做的事情,而不仅仅是摆脱findViewById。
您必须具有经验丰富的场景,其中ListView或者RecyclerView或者仅出于普通布局而使用数据模型将相关信息添加到布局中。
即使我们在MainActivity中获得了视图布局的字段名称,它仍然需要我们编写许多重复的代码段。
假设我们有一个布局,其中可以动态添加DataModel.java类中的数据,并在特定时间间隔后更新值。
下面的代码片段显示了将数据从数据模型类提供给布局时数据绑定的示例实现。

activity_main.xml

<layout xmlns:android="https://schemas.android.com/apk/res/android">

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

      <ImageView
          android:id="@+id/imageView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"

      <TextView
          android:id="@+id/name"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"

      <TextView
          android:id="@+id/summary"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" 
  </LinearLayout>
</layout>

下面给出了DataModel.java类。

public class DataModel {

  String name;
  int image;
  String summary;

  public DataModel(int image, String name, String summary) {

      this.name = name;
      this.summary = summary;
      this.image = image;
  }

  public int getImage() {
      return image;
  }

  public void setImage(int image) {
      this.image = image;
  }

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public String getSummary() {
      return summary;
  }

  public void setSummary(String summary) {
      this.summary = summary;
  }
}

MainActivity.java在下面给出。

public class MainActivity extends AppCompatActivity {

  ActivityMainBinding binding;
  Timer timer;
  int i = 0;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

      DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0");
      binding.imageView.setImageResource(dataModel.getImage());
      binding.name.setText(dataModel.getName());
      binding.summary.setText(dataModel.getSummary());

      timer= new Timer();
      timer.scheduleAtFixedRate(new TimerTask() {
          @Override
          public void run() {

              runOnUiThread(new Runnable() {
                  @Override
                  public void run() {

                      if (i == 0) {
                          DataModel dataModel = new DataModel(R.drawable.lollipop, "Android Lollipop", "Android 5.0");
                          binding.imageView.setImageResource(dataModel.getImage());
                          binding.name.setText(dataModel.getName());
                          binding.summary.setText(dataModel.getSummary());

                          i=1;

                      } else {
                          
                          i=0;
                          DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0");
                          binding.imageView.setImageResource(dataModel.getImage());
                          binding.name.setText(dataModel.getName());
                          binding.summary.setText(dataModel.getSummary());

                      }
                  }
              });
          }
      }, 3000, 3000); 
  }
}

我们使用了一个计时器,该计时器每3秒钟会不断交替更改布局数据。
如您所见,setText和setImageResource的重复代码太多。
DataBinding允许我们直接在xml布局中分配来自DataModel类的数据。

Android数据绑定代码

我们在xml中定义了DataModel类变量对象,如下图所示。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android">

  <data>
      <variable
          name="data"
          type="com.theitroad.advanceddatabinding.DataModel" 
  </data>

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

      <ImageView
          android:id="@+id/imageView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:src="@{data.image}" 

      <TextView
          android:id="@+id/name"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{data.name}" 

      <TextView
          android:id="@+id/summary"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{data.summary}" 
  </LinearLayout>
</layout>

DataBinding具有自己的布局文件表达语言。
它允许我们直接在xml属性中分配数据。

  • <data>放在布局中,用作布局标签中使用的变量的包装,也可以用于导入您的工作示例中所需的类型View类型,如下所示:
    为了方便起见,alias属性用于为导入类型分配名称。

  • <variable>包含名称和类型,分别描述变量名称及其全名(包括程序包名称)

  • @ {}容器,用于描述表达式。
    例如,显示字段名称或者使用表达式和运算符显示数据(我们将在后面介绍)

MainActivity.java在下面给出。

<data>
  <import type="android.view.View" alias="v"
</data>

现在看起来更干净,更易读了!

从上面的代码中得出的推论很少:

  • 将DataModel对象直接设置为绑定对象,如下所示
    binding.setData(dataModel);

setData方法是从xml布局中定义的变量名生成的

  • ImageView是一个源属性。
    为了让BindingAdapter能够识别android:src属性,我们在MainActivity.java中明确定义为

Android数据绑定应用程序输出

实际应用程序的输出如下。

DataBinding提供的表达语言要使用的不仅仅是指定数据。
我们可以根据某些条件指定xml属性,如下所示。

public class MainActivity extends AppCompatActivity {

  ActivityMainBinding binding;
  Timer timer;
  int i = 0;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

      DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0");
      binding.setData(dataModel);

      timer = new Timer();
      timer.scheduleAtFixedRate(new TimerTask() {
          @Override
          public void run() {

              runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                      if (i == 0) {
                          DataModel dataModel = new DataModel(R.drawable.lollipop, "Android Lollipop", "Android 5.0");
                          binding.setData(dataModel);
                          i = 1;
                      } else {
                          i = 0;
                          DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0");
                          binding.setData(dataModel);
                      }
                  }
              });
          }
      }, 3000, 3000); //End of your timer code.
  }

  @BindingAdapter({"android:src"})
  public static void setImageViewResource(ImageView imageView, int resource) {
      imageView.setImageResource(resource);
  }
}

上面的行可以用更紧凑的形式编写:

@BindingAdapter({"android:src"})
  public static void setImageViewResource(ImageView imageView, int resource) {
      imageView.setImageResource(resource);
  }