Android RecyclerView #
Begriffe #
- Der Adapter passt die Schnittstelle einer Liste oder eines anderen Speicher an, damit die RecyclerView sie verwenden kann. In der ListView wurde bereits ein Adapter eingeführt. In der RecyclerView werden weitere Funktionen des Adapters verwendet.
- Der ViewHolder zwischenspeichert die Views einer Zeile.
- Der ItemDecoration kann Dekoration um die Elemente oder auch Trennlinien hinzufügen.
- Der ItemAnimator kann hinzufügen, entfernen und scrolling von Elementen animieren.
- Der LayoutManager ordnet die Elemente in der RecyclerView. LinearLayoutManager oder GridLayoutManager sind bereits für die Entwickler erstellt.
Adapter #
Nachdem Daten in der zugrunde liegenden Datenquelle angepasst wurden, muss der Adapter aktualisiert werden. Dafür gibt es 4 Möglichkeiten:
notifyDataSetChanged(); // alles wird aktualisiert
notifyItemChanged(positionToUpdate); // nur ein Listeneintrag wird aktualisiert
notifyItemInserted(insertPosition); // nur hinzugefügte Daten werden geladen
notifyItemRemoved(removePosition); // Listeneinträge werden entfernt
Der ViewHolder ist eine Verbesserung gegenüber der ListView. Da das findViewById(…) relativ zeitintensiv ist, werden die benötigten Views im ViewHolder zwischengespeichert. Dadurch muss diese Funktion nur beim Instanzieren des ViewHolder aufgerufen werden. Ausserdem werden nur soviele ViewHolders erzeugt, wie auch auf dem Display angezeigt werden können. Beim Scrollen werden die ViewHolder mit anderen Daten gefüllt (onBindViewHolder(…)), aber es werden keine neuen ViewHolder instanziert.
Manchmal müssen Funktionen der Activity oder des Fragments aus dem Adapter heraus aufgerufen werden. Das kann mit Hilfe des Observer-Pattern gelöst werden. Im untenstehenden Beispiel ist das mit dem selbst erstellten ItemSelectionListener Interface gelöst.
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.ViewHolder> {
public class ViewHolder extends RecyclerView.ViewHolder {
public View itemRoot;
public TextView textView;
public ViewHolder(View itemRoot, TextView textView) {
super(itemRoot);
this.itemRoot = itemRoot;
this.textView = textView;
}
}
private Notes notes;
private ItemSelectionListener selectionListener;
public NotesAdapter(Notes notes, ItemSelectionListener sl) {
this.notes = notes;
this.selectionListener = sl;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layinf = LayoutInflater.from(parent.getContext());
View v = layinf.inflate(R.layout.rowlayout, parent, false);
TextView textView = (TextView) v.findViewById(R.id.textView);
ViewHolder viewHolder = new ViewHolder(v, textView);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final Note note = notes.get(position);
holder.textView.setText(note.getTitle());
holder.itemRoot.setOnClickListener((View v) -> selectionListener.onItemSelected(position));
}
@Override
public int getItemCount() { return notes.size();}
}
Verwendung #
public class NotesListFragment extends Fragment {
private ItemSelectionListener itemSelectionCallback = null;
private RecyclerView recyclerView;
private LinearLayoutManager layoutManager;
private NotesAdapter adapter;
@Override
public View onCreateView(LayoutInflater inf, ViewGroup container,
Bundle saveinst) {
View rootView = inf.inflate(R.layout.fragment, container, false);
recyclerView = rootView.findViewById(R.id.recyclerView);
// Eine Optimierung, wenn sich die Displaygroesse der Liste nicht
// ändern wird.
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
Application app = (Application) getActivity().getApplication();
adapter = new NotesAdapter(app.getNotes(), itemSelectionCallback);
recyclerView.setAdapter(adapter);
return rootView;
}
}