Поиск по сайту:

Привязка данных Android RecyclerView


В этом руководстве мы обсудим и реализуем RecyclerView с использованием привязки данных в нашем приложении для Android.

Android RecyclerView DataBinding

Чтобы узнать основы Android DataBinding, посетите классы адаптеров. Наконец, мы покажем, как напрямую передать объект адаптера в XML.

Начиная

Добавьте следующий код в файл build.gradle вашего приложения:

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

Добавьте следующую зависимость.

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

Структура проекта

Код

Код класса DataModel.java приведен ниже:

package com.journaldev.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.journaldev.androidrecyclerviewdatabinding;

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

import com.journaldev.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.journaldev.androidrecyclerviewdatabinding.DataModel" />

        <variable
            name="itemClickListener"
            type="com.journaldev.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.journaldev.androidrecyclerviewdatabinding;

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

Код для класса MyRecyclerViewAdapter.java приведен ниже:

package com.journaldev.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.journaldev.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 с использованием привязки данных

Благодаря привязке данных мы можем дополнительно сократить шаблонный код в нашем MainActivity.java, передав экземпляр адаптера в XML внутри атрибута android:adapter, как показано ниже: 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.journaldev.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);

AndroidRecyclerViewDataBinding

Ссылка на проект на гитхабе