Android RecyclerView

Terms

  • The Adapter adapts the interface of a list or other store so that the RecyclerView can use it. An adapter has already been introduced in the ListView. In the RecyclerView, other functions of the adapter are used.
  • The ViewHolder caches the views of a row.
  • The ItemDecoration can add decoration around the items or even separators.
  • The ItemAnimator can animate adding, removing and scrolling of items.
  • The LayoutManager arranges the items in the RecyclerView. LinearLayoutManager or GridLayoutManager are already created for the developers.

Adapter

After data in the underlying data source has been adjusted, the adapter must be updated. There are 4 ways to do this:

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 

The ViewHolder is an improvement over the ListView. Since the findViewById(...) is relatively time-consuming, the required views are cached in the ViewHolder. Thus this function must be called only when instantiating the ViewHolder. Furthermore, only as many ViewHolders are created as can be shown on the display. When scrolling, the ViewHolders are filled with other data (onBindViewHolder(...)), but no new ViewHolders are instantiated.

Sometimes functions of the activity or fragment need to be called from the adapter. This can be solved using the Observer pattern. In the example below this is solved with the custom ItemSelectionListener interface.

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();}
}

Usage

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;
  }
}
Previous