How can I exclude a dependency from the ListView onItemClick / getView and its row types?

As a simplified example, consider ListView

one that can contain both subcategories and book titles. Clicking on the title of a book should start a new action that displays the cover. If a subcategory is clicked, a new list of books and categories is displayed.

Interface

A is Row

defined as follows.

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

      

I would like to know how to prevent dependency on ListView

ArrayAdapter

as well as performer onItemClickListener

from performers Row

(eg Book

and Category

).

One of the driving forces behind this requirement is the Do Not Repeat Yourself (DRY) principle: the implementation ArrayAdapter

does not need to change when new string types are introduced.

0


source to share


2 answers


Pardon my "UML" with chicken, 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 developer OnItemClickListener

has this way:

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 interface Row

has a method with the signature void onClick()

and there Category

and Book

implementation Row

, which provide the necessary behavior.

UML Diagram

+1


source


Another possibility is to use the setTag / getTag methods for each View item in the list - this allows you to attach "Book" or "Category" to the appropriate string.

To do this, for each of the listed elements to work, it is necessary to implement a common interface that has a corresponding method to be called when pressed.

For example:

interface Selectable {
    void onSelected();  // Add parameters if necessary...
}

      

In your list adapter:



public View getView(int position, View convertView, ViewGroup parent) {    
    View itemView;  // Logic to get the appropriate view for this row.

    Selectable theObjectBeingRepresented;
    //
    // Logic to assign a Book/Category, etc to theObjectBeingRepresented.
    // In this example assume there is a magic Book being represented by 
    // this row.
    //
    Book aMagicBook = new Book();
    theObjectBeingRepresented = aMagicBook;

    // If all objects that will be contained in your list implement the 
    // 'Selectable' interface then you can simply call setTag(...) with
    // the object you are working with (otherwise you may need some conditional logic)
    //
    itemView.setTag( SELECTABLE_ITEM_KEY, theObjectBeingRepresented );
}

      

Then when the item is clicked:

void onItemClick(AdapterView<?> adapterView, View view, int rowIndex, long rowId) 
{ 
   Selectable item = (Selectable)view.getTag( SELECTABLE_ITEM_KEY );

   // Depending on how you are populating the list, you may need to check for null
   // before operating on the item..
   if( null != item ) {
       item.onClick();  // Appropriate implementation called...
   }
}

      

A little more detail on the setTag method: setTag documentation

Hope it helps ...

0


source







All Articles