如何消除ListView的onItemClick / getView及其行类型的依赖性?

时间:2012-03-15 14:27:25

标签: android listview dependencies dry separation-of-concerns

作为简化示例,请考虑可以包含子类别和书名的ListView。如果单击书名,则应开始显示封面图像的新活动。如果单击子类别,则会显示新的书籍和类别列表。

Row接口定义如下。

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

我想知道如何防止ListView的{​​{1}}以及ArrayAdapter实施者onItemClickListener的实施者的依赖关系(例如, RowBook)。

推动此要求的一个因素是“不要重复自己”(DRY)原则:引入新行类型时,Category实现不需要更改。

2 个答案:

答案 0 :(得分:1)

原谅我下面的鸡抓“UML”,但这就是我的表现方式。

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

OnItemClickListener的实施者有这样的方法:

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

然后RowProvider有这样的方法:

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

然后Row接口有一个签名为void onClick()的方法,CategoryBook的{​​{1}}实现提供了必要的行为。

UML Diagram

答案 1 :(得分:0)

另一种可能性是在列表中的每个项目的View上使用setTag / getTag方法 - 这允许您将“Book”或“Category”附加到其相应的行。

为此,每个“列出的”项应该实现一个公共接口,该接口具有在单击时调用的适当方法。

例如:

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

在列表适配器中:

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

然后点击某个项目时:

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...
   }
}

关于setTag方法的更多细节: setTag documentation

希望这会有所帮助......