Android-Programmierung RecyclerView
Willemers Informatik-Ecke
Unter Android-Versionen bis 4 war die ListView die einzig praktische Art, eine scrollbare Liste zu erstellen. Seit Android 5 ist die RecyclerView verfügbar.

Activity mit einem einfachen Array

Die Activity soll einen Lagerbestand in einer Liste darstellen. Im einfachsten Fall ist dies eine ArrayList hier mit dem Namen lager, die in der Methode initializeData mit ein paar Werten gefüllt wird. Wie die Klasse Lager aussieht, wird hier nicht näher erörtert.
public class MainActivity extends AppCompatActivity {

    ArrayList<Lager> lager = new ArrayList<>();
    int maxLagerId = 1;

    private void initializeData() {
        lager.add(new Lager(12, 12.5, "Lakritz"));
        lager.add(new Lager(5, 10, "Micky Maus"));
        lager.add(new Lager(9, 29.9, "Klebstoff"));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // soweit wie immer, nun werden die Daten initialisiert.
        initializeData();
        // Die RecyclerView einrichten
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.liste);
        // Den Adapter für Darstellung und Daten erstellen und aktivieren
        MeinRecycleAdapter adapter = new MeinRecycleAdapter(lager);
        recyclerView.setAdapter(adapter);
        // Das Layout als LinearLayout anlegen
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}

Nachdem in onCreate die Daten initialisiert wurden, wird die RecyclerView-Referenz per findViewById ermittelt. Für die Verbindung zwischen der RecyclerView und den Daten wird ein Adapter erstellt. Anschließend wird das Layout festgelegt, in dem die Listenelemente dargestellt werden sollen.

Die Layout-XML-Dateien

Wie bei jeder Activity wird auch hier für die Anordnung der Kontrollelemente eine XML-Layout-Datei angelegt.

Die Activity-Layout-XML

In der Layout-XML-Datei wird für dieses Programm nur eine RecyclerView angelegt, die den gesamten Bildschirm füllt.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/liste"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toBottomOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

Das Layout der Listenelemente

Jedes Element der RecyclerView besteht wiederum aus Kontrollelementen, meist nur TextViews. In diesem Fall gibt es für jedes Attribut der Klasse Lager, id, anzahl und bezeichnung, ein eigenes Feld.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tvLiId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="10sp"
        android:paddingEnd="10sp"
        android:text="Id" />

    <TextView
        android:id="@+id/tvLiAnzahl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="10sp"
        android:paddingEnd="10sp"
        android:text="Anzahl" />

    <TextView
        android:id="@+id/tvLiBez"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="10sp"
        android:paddingEnd="10sp"
        android:text="Bez" />

Im einfachsten Fall wie hier, kann ein LinearLayout verwendet werden. Es stellt die drei Attribute von links nach rechts horizontal dar.

LayoutManager

Die RecyclerView verwendet für die Anordnung seiner Elemente innerhalb der Liste typischerweise folgende LayoutManager:

Der Adapter

Der Adapter verbindet die Daten mit der RecyclerView. Da man eigene Daten hat, erzeugt man eine eigene Klasse, die die Klasse RecyclerView.Adapter erweitert.

Dem Kontruktor übergibt man die Referenz auf die eigenen Daten. In diesem Fall ist es die Lager-ArrayList, bei Datenbanken oder Content-Providern wäre dies ein Cursor. Aus diesen Daten kann der Adapter zunächst die Anzahl der Daten ermitteln, die es in der überschriebenen Methode getItemCount zurückgibt.

public class MeinRecycleAdapter extends RecyclerView.Adapter {

    ArrayList lager; // Die Daten, um die es geht

    /**
     * Der Konstruktor übernimmt die Daten vom Aufrufer
     */
    MeinRecycleAdapter(ArrayList lager){
        this.lager = lager;
    }

    @Override
    public int getItemCount() {
        return lager.size();
    }
Für das Füllen des Listeninhalts verwendet der Adapter eine interne Klasse ViewHolder, die RecyclerView.ViewHolder erweitert. Im Konstruktor werden die Kontrollelemente aus der Layoutdatei ermittelt. Diese werden später benötigt, wenn sie bei onBindViewHolder mit Daten gefüllt werden.
public class MeinRecycleAdapter extends RecyclerView.Adapter {

    // ...
 
    /**
     * ViewHolder kümmert sich um die Ansicht des Elements
     */
    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView tvId, tvAnz, tvBez;
        public ViewHolder(View view) {
            super(view);
            tvId = (TextView)itemView.findViewById(R.id.tvLiId);
            tvAnz = (TextView)itemView.findViewById(R.id.tvLiAnzahl);
            tvBez = (TextView)itemView.findViewById(R.id.tvLiBez);
        }
    }

    /**
     * Initialisiert den ViewHolder
     * @param parent
     * @param viewType
     * @return
     */
    @NonNull
    @Override
    public MeinRecycleAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.listelement,
                parent, false);
        MeinRecycleAdapter.ViewHolder pvh = new MeinRecycleAdapter.ViewHolder(v);
        return pvh;
    }

    /**
     * Die Daten werden an die Elemente der Liste zur Darstellung übergeben.
     * @param holder
     * @param pos
     */
    @Override
    public void onBindViewHolder(
            @NonNull MeinRecycleAdapter.ViewHolder holder, int pos) {
        holder.tvId.setText("" + lager.get(pos).id);
        holder.tvAnz.setText("" + lager.get(pos).anz);
        holder.tvBez.setText(lager.get(pos).bez);

    }
}