问题
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.
回答1:
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.
回答2:
Another possibility is to use the setTag/getTag methods on each item's View in the list - this allows you to attach the 'Book' or 'Category' to its appropriate row.
For this to work each of the 'listed' items should implement a common interface that has an appropriate method to be called when it is clicked.
For instance:
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 an 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 bit more detail on the setTag method: setTag documentation
Hope this helps...
来源:https://stackoverflow.com/questions/9721790/how-can-i-eliminate-the-dependency-from-of-a-listviews-onitemclick-getview-and