我一直在学习android公共软件编程教程,在教程5,额外学分2中,挑战是根据对象的“type name”(餐厅的“type”属性,即字符串)使用多个布局在列表视图中显示行。因此,它建议在自定义arrayadapter中重写getItemViewTypegetViewTypeCount。此外,android docs和其他online recipesblog posts也表明了这一点。
在这种情况下,遵循这个配方并重写这两个方法可以很好地工作,但会导致基于检查餐厅“type”属性值的冗余逻辑。例如(注意,这个适配器是一个内部类,restaurants是声明为外部活动成员的餐厅对象的arraylist):

class RestaurantsAdapter extends ArrayAdapter<Restaurant> {

  private static final int ROW_TYPE_DELIVERY = 0;
  private static final int ROW_TYPE_TAKE_OUT = 1;
  private static final int ROW_TYPE_SIT_DOWN = 2;

  RestaurantsAdapter() {
    super(LunchListActivity.this, android.R.layout.simple_list_item_1, restaurants);
  }

  public int getViewTypeCount() {
    return 3;
  }

  public int getItemViewType(int position) {
    String type = restaurants.get(position).getType();
    if (type == "delivery") {
      return ROW_TYPE_DELIVERY;
    } else if (type == "take_out") {
      return ROW_TYPE_TAKE_OUT;
    } else {
      return ROW_TYPE_SIT_DOWN;
    }
  }

  // Sets the icon, name and address of the Restaurant for the view.
  public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    RestaurantHolder viewHolder;

    if (row == null) {
      LayoutInflater inflater = getLayoutInflater();
      switch (getItemViewType(position)) {
        case ROW_TYPE_DELIVERY:
          row = inflater.inflate(R.layout.row_delivery, null);
          break;
        case ROW_TYPE_TAKE_OUT:
          row = inflater.inflate(R.layout.row_take_out, null);
          break;
        default:
          row = inflater.inflate(R.layout.row_sit_down, null);
          break;
      }

      viewHolder = new RestaurantHolder(row);
      row.setTag(viewHolder);
    } else {
      viewHolder = (RestaurantHolder)row.getTag();
    }

    viewHolder.populateFrom(restaurants.get(position));

    return row;
  }

}

令我困扰的是重复逻辑(if/else在getItemViewType中,而switchgetView中)。因此,我将实现更改为:
class RestaurantsAdapter extends ArrayAdapter<Restaurant> {

  RestaurantsAdapter() {
    super(LunchListActivity.this, android.R.layout.simple_list_item_1, restaurants);
  }

  // Sets the icon, name and address of the Restaurant for the view.
  public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    RestaurantHolder viewHolder;

    if (row == null) {
      LayoutInflater inflater = getLayoutInflater();
      if (restaurants.get(position).getType() == "delivery") {
        row = inflater.inflate(R.layout.row_delivery, null);
      } else if (restaurants.get(position).getType() == "take_out") {
        row = inflater.inflate(R.layout.row_take_out, null);
      } else {
        row = inflater.inflate(R.layout.row_sit_down, null);
      }
      viewHolder = new RestaurantHolder(row);
      row.setTag(viewHolder);
    } else {
      viewHolder = (RestaurantHolder)row.getTag();
    }

    viewHolder.populateFrom(restaurants.get(position));

    return row;
  }

}

这实现了动态加载三个xml布局中的一个的目标,消除了冗余逻辑,稍微减少了代码与布局数量的耦合,并且不需要重写getViewTypeCountgetItemViewType
我的问题是:如果没有必要,为什么要重写这两种方法?

最佳答案

如果没有必要,为什么要重写这两个方法?
添加几十个餐厅,所有不同类型,并看着你的行回收乱七八糟当你滚动,给定你的实现如上所示。
getItemViewType()getViewTypeCount()是为了确保行回收工作。android将维护单独的对象池,并且只将一行返回给正确类型的recycle。
在您的解决方案中,您可以对R.layout.row_delivery行进行充气,然后在您真正需要R.layout.row_sit_down行时将其交还给您进行回收。
顺便说一下,不要在inflate(R.layout.row_take_out, null)中使用AdapterView。要正确处理RelativeLayout规则,请使用inflate(R.layout.row_take_out, parent, false)

07-24 09:47
查看更多