Android Apps schlank halten: Data Binding und RecyclerView optimal nutzen

Einführung in Android RecyclerView mit Data Binding

In diesem Beitrag zeigen wir, wie man RecyclerView in einer Android-App mit Data Binding integriert. Data Binding reduziert erheblich den Boilerplate-Code, was die Entwicklung effizienter und lesbarer macht. Hier erklären wir, wie Data Binding in Kombination mit dem ViewHolder-Pattern genutzt wird und wie sich Adapter-Klassen dadurch leicht verallgemeinern lassen. Schließlich demonstrieren wir, wie man ein Adapter-Objekt direkt im XML-Code übergibt.

Los geht’s: Erste Schritte

Bevor wir beginnen, müssen wir sicherstellen, dass Data Binding in unserer Android-App aktiviert ist. Dazu fügen wir folgenden Code in die build.gradle-Datei ein:

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

Zusätzlich fügen wir folgende Abhängigkeit hinzu:

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

Projektstruktur

In der folgenden Anwendung werden wir die Daten direkt aus dem XML in den Adapter-Zeilen der RecyclerView laden. Außerdem setzen wir die onClickListener-Methoden direkt in den Layout-Zeilen.

Code für das Datenmodell

Der Code für die DataModel.java-Klasse sieht folgendermaßen aus:

package com.beispiel.androidrecyclerviewdatabinding;

public class DataModel {

    public String androidVersion, androidName;

    public DataModel(String androidName, String androidVersion) {
        this.androidName = androidName;
        this.androidVersion = androidVersion;
    }
}

Layout für die Hauptaktivität

Das Layout für die activity_main.xml-Datei ist wie folgt definiert:

<?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>
        <!-- Hier könnten Daten gebunden werden -->
    </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>

Hauptaktivität in Java

Der Code für die MainActivity.java-Datei ist wie folgt:

package com.beispiel.androidrecyclerviewdatabinding;

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

import com.beispiel.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 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);
    }
}

Layout für jede Zeile in der RecyclerView

Das Layout für jede Zeile in der RecyclerView ist in item_row.xml definiert:

<?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.beispiel.androidrecyclerviewdatabinding.DataModel" />
        <variable
            name="itemClickListener"
            type="com.beispiel.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>

Im obigen Layout wird die DataModel-Referenz sowie eine Referenz auf das CustomClickListener-Interface, dessen Methode innerhalb der CardView aufgerufen wird, übergeben.

CustomClickListener Interface

Das CustomClickListener.java Interface sieht wie folgt aus:

package com.beispiel.androidrecyclerviewdatabinding;

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

Adapter-Klasse für RecyclerView

Die Adapter-Klasse MyRecyclerViewAdapter.java:

package com.beispiel.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.beispiel.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, "Sie haben " + f.androidName + " angeklickt",
                Toast.LENGTH_LONG).show();
    }
}

Adapter direkt im XML binden

Dank Data Binding kann der Adapter nun direkt im XML-Code übergeben werden, was den Code in MainActivity.java weiter vereinfacht. In activity_main.xml wird der Adapter wie folgt gesetzt:

<?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.beispiel.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>

In MainActivity.java wird der Adapter nun folgendermaßen gesetzt:

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

Durch diese Technik müssen wir die RecyclerView nicht mehr manuell in der Aktivität initialisieren. Das macht den Code sauberer und die Anwendung effizienter.

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren:

centron Managed Cloud Hosting in Deutschland

Mocking Void Methods mit EasyMock

Anleitung, JavaScript
Mocking Void Methods mit EasyMock Im Unit Testing ist Mocking eine essentielle Technik, die Entwicklern ermöglicht, das Verhalten komplexer Objekte zu simulieren. EasyMock ist ein beliebtes Framework zur Erstellung von…