Android RecyclerView数据绑定

时间:2020-02-23 14:29:11  来源:igfitidea点击:

在本教程中,我们将在Android应用程序中讨论和实现RecyclerView using Data Binding。

Android RecyclerView数据绑定

为了了解Android DataBinding的基础知识,请访问本教程。

数据绑定大大减少了样板代码。
其中我们将学习如何使用具有ViewHolder模式的RecyclerView来实现DataBinding。

另外,我们还将了解数据绑定如何使通用化Adapter类变得容易。

最后,我们将演示如何直接在XML中传递适配器对象。

入门

在您应用的" build.gradle"中添加以下代码:

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

添加以下依赖项。

implementation 'com.android.support:design:28.0.0'

项目结构

在以下应用程序中,我们将使用<data>将数据从XML加载到RecyclerView的适配器行中。
另外,我们将在布局行本身中设置onClickListener方法。

代码

下面给出了DataModel.java类的代码:

package com.theitroad.androidrecyclerviewdatabinding;

public class DataModel {

  public String androidVersion, androidName;

  public DataModel(String androidName, String androidVersion) {

      this.androidName = androidName;
      this.androidVersion = androidVersion;
  }
}

下面给出了" activity_main.xml"布局的代码:

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

  <data>
      
  </data>

  <android.support.constraint.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <android.support.v7.widget.RecyclerView
          android:id="@+id/recyclerView"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintTop_toTopOf="parent" 

  </android.support.constraint.ConstraintLayout>
</layout>

MainActivity.java

package com.theitroad.androidrecyclerviewdatabinding;

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;

import com.theitroad.androidrecyclerviewdatabinding.databinding.ActivityMainBinding;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

  private ActivityMainBinding binding;

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

  private void populateData() {
      List<DataModel> dataModelList = new ArrayList<>();

      dataModelList.add(new DataModel("Android Oreo", "8.1"));
      dataModelList.add(new DataModel("Android Pie", "9.0"));
      dataModelList.add(new DataModel("Android Nougat", "7.0"));
      dataModelList.add(new DataModel("Android Marshmallow", "6.0"));

      MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(dataModelList, this);
      binding.setMyAdapter(myRecyclerViewAdapter);
  }
}

RecyclerView的每一行的布局都在" item_row.xml"中定义。

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

  <data>

      <variable
          name="model"
          type="com.theitroad.androidrecyclerviewdatabinding.DataModel" 

      <variable
          name="itemClickListener"
          type="com.theitroad.androidrecyclerviewdatabinding.CustomClickListener" 
  </data>

  <android.support.v7.widget.CardView
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:onClick="@{() -> itemClickListener.cardClicked(model)}"
      app:cardUseCompatPadding="true">

      <LinearLayout
          android:layout_width="wrap_content"
          android:layout_margin="8dp"
          android:layout_height="wrap_content"
          android:orientation="vertical">

          <TextView
              android:id="@+id/tvAndroidName"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@{model.androidName}"
              android:textAppearance="@style/TextAppearance.AppCompat.Headline" 

          <TextView
              android:id="@+id/tvAndroidVersion"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@{model.androidVersion}"
              android:textAppearance="@style/TextAppearance.AppCompat.Subhead" 

      </LinearLayout>

  </android.support.v7.widget.CardView>

</layout>

在数据标签内,我们传递了两个变量-一个DataModel参考和一个CustomClickListener接口的参考,该接口的方法在CardView中被调用。

下面定义了CustomClickListener.java的代码:

package com.theitroad.androidrecyclerviewdatabinding;

public interface CustomClickListener {
  void cardClicked(DataModel f);
}

下面给出了MyRecyclerViewAdapter.java类的代码:

package com.theitroad.androidrecyclerviewdatabinding;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.Toast;

import java.util.List;

import com.theitroad.androidrecyclerviewdatabinding.databinding.ItemRowBinding;

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> implements CustomClickListener {

  private List<DataModel> dataModelList;
  private Context context;

  public MyRecyclerViewAdapter(List<DataModel> dataModelList, Context ctx) {
      this.dataModelList = dataModelList;
      context = ctx;
  }

  @Override
  public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                             int viewType) {
      ItemRowBinding binding = DataBindingUtil.inflate(
              LayoutInflater.from(parent.getContext()),
              R.layout.item_row, parent, false);

      return new ViewHolder(binding);
  }

  @Override
  public void onBindViewHolder(ViewHolder holder, int position) {
      DataModel dataModel = dataModelList.get(position);
      holder.bind(dataModel);
      holder.itemRowBinding.setItemClickListener(this);
  }

  @Override
  public int getItemCount() {
      return dataModelList.size();
  }

  public class ViewHolder extends RecyclerView.ViewHolder {
      public ItemRowBinding itemRowBinding;

      public ViewHolder(ItemRowBinding itemRowBinding) {
          super(itemRowBinding.getRoot());
          this.itemRowBinding = itemRowBinding;
      }

      public void bind(Object obj) {
          itemRowBinding.setVariable(BR.model, obj);
          itemRowBinding.executePendingBindings();
      }
  }

  public void cardClicked(DataModel f) {
      Toast.makeText(context, "You clicked " + f.androidName,
              Toast.LENGTH_LONG).show();
  }
}

为了将数据传递到XML副本,我们使用ʻitemRowBinding.setVariable(BR.model,obj);`将其绑定。

为了立即执行数据绑定,ʻexecutePendingBindings()`很重要。
否则会填充错误的视图。

setVariable()和setModel()之间的区别

在不知道数据类型的一般情况下使用setVariable()。

setModel()是自动生成的。
我们可以使用以下内容代替" holder.bind(dataModel);"。

holder.itemRowBinding.setModel(dataModel);

使用数据绑定在RecyclerView XML中传递适配器实例

由于数据绑定,我们可以通过在android:adapter属性内的XML中传递适配器实例,从而进一步减少MainActivity.java中的样板代码,如下所示:

activity_main.xml

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

  <data>

      <variable
          name="myAdapter"
          type="com.theitroad.androidrecyclerviewdatabinding.MyRecyclerViewAdapter" 
  </data>

  <android.support.constraint.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <android.support.v7.widget.RecyclerView
          android:id="@+id/recyclerView"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:adapter="@{myAdapter}"
          app:layoutManager="android.support.v7.widget.LinearLayoutManager"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintTop_toTopOf="parent" 

  </android.support.constraint.ConstraintLayout>
</layout>

在MainActivity.java中,我们现在可以通过以下方式设置适配器:

MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(dataModelList, this);
binding.setMyAdapter(myRecyclerViewAdapter);

因此,甚至不需要在Activity类中初始化RecyclerView。