Search code examples
androidlistviewdependenciesdryseparation-of-concerns

How can I eliminate the dependency from of a ListView's onItemClick/getView and its row types?


As a simplified example, consider a ListView that can contain both sub-categories and book titles. If a book title is clicked, a new activity should start that shows the cover image. If a sub-category is clicked, a new list of books and categories is displayed.

A Row interface is defined as follows.

interface Row {
   void onClick();
   void draw(View v);
}

I would like to know how to prevent a dependency from the ListView's ArrayAdapter as well as from the implementer of onItemClickListener on the Row implementers (e.g.,Book and Category).

One of the forces driving this requirement is the "don't repeat yourself" (DRY) principle: the ArrayAdapter implementation does not need to change when new row types are introduced.


Solution

  • Forgive my chicken-scratched "UML" below, but here's how I do it.

    class ListAdapter extends ArrayAdapter<Row<?>> {
    ...
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = listViewRowViewRecycler.getView(convertView);
            rowProvider.get().getRow(position).draw(view);
            return view;
        }
    }
    

    The implementer of OnItemClickListener has a method like this:

    void onItemClick(AdapterView<?> adapterView, View view, int rowIndex, long rowId)
    {
       rowProvider.onItemClick(rowIndex);
    }
    

    Then RowProvider has a method like this:

    void onItemClick(int rowIndex) {
        rowList.get(rowIndex).onClick();
    }
    

    Then the Row interface has a method with signature void onClick() and there are Category and Book implementations of Row that provide the necessary behavior.

    UML Diagram