アンドロイドのRecyclerViewデータバインディング
このチュートリアルでは、Androidアプリケーションでのデータバインディングを使用してRecyclerViewを説明し、実装していきます。
アンドロイドのRecyclerViewとデータバインディング
Android DataBindingの基本を知るために、このチュートリアルを参照してください。Data Bindingは冗長なコードを大幅に削減します。ここでは、ViewHolderパターンを持つRecyclerViewでDataBindingを実装する方法を学びます。また、Data Bindingを使用することで、アダプタークラスを汎用化することが容易になります。最後に、XML内で直接アダプターオブジェクトを渡す方法を示します。
始める
Your app’s build.gradleに以下のコードを追加してください。
android{
...
dataBinding {
enabled = true
}
...
}
以下の依存関係を追加してください。
implementation 'com.android.support:design:28.0.0'
プロジェクトの構造
以下のアプリケーションでは、を使用してRecyclerViewのアダプター行にXMLからデータを読み込みます。また、レイアウトの行自体にonClickリスナーメソッドを設定します。
コードを日本語で自然に言い換えてください。オプションは一つだけで構いません。
コード (Kōdo)
下記はDataModel.javaクラスのコードです。
package com.scdev.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を日本語で自然に言い換える。ただし、一つのオプションで構いません。
メインアクティビティー.java
package com.scdev.androidrecyclerviewdatabinding;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import com.scdev.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.scdev.androidrecyclerviewdatabinding.DataModel" />
<variable
name="itemClickListener"
type="com.scdev.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>
データタグの内部で、2つの変数を渡します。1つはDataModelの参照であり、もう1つはCustomClickListenerインターフェースの参照であり、そのメソッドがCardView内で呼び出されます。CustomClickListener.javaのコードは、以下に定義されています。
package com.scdev.androidrecyclerviewdatabinding;
public interface CustomClickListener {
void cardClicked(DataModel f);
}
以下に、MyRecyclerViewAdapter.javaクラスのコードが示されています。
package com.scdev.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.scdev.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でデータバインディングを使用して、Adapterのインスタンスを渡す方法
以下のようにactivity_main.xml内のandroid:adapter属性にアダプタインスタンスを渡すことで、データバインディングのおかげでMainActivity.javaの冗長なコードをさらに削減することができます。
<?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.scdev.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);
上記のアプリケーションの出力結果は以下の通りですので、アクティビティクラスでRecyclerViewを初期化する必要はありません。このチュートリアルは以上です。プロジェクトは以下のリンクからダウンロードできます。
アンドロイドのRecyclerViewデータバインディング
Githubプロジェクトのリンク