【问题标题】:Why do recipes promote overriding getItemViewType and getViewTypeCount when it doesn't seem necessary?为什么食谱在似乎没有必要时提倡覆盖 getItemViewType 和 getViewTypeCount?
【发布时间】:2012-04-22 17:13:22
【问题描述】:

我一直在学习 Commonsware Android Programming Tutorials 和教程 5,额外得分 2,挑战是根据对象的“类型名称”(餐厅的“ type”属性,它是一个字符串)。因此,它建议在自定义 ArrayAdapter 中覆盖 getItemViewTypegetViewTypeCount。此外,android docs 和其他online recipesblog posts 建议相同。

在这种情况下,遵循这个配方并覆盖这两种方法可以正常工作,但会导致基于检查该餐厅“类型”属性的值的冗余逻辑。例如(注意这个适配器是一个内部类,restaurants 是一个声明为外部 Activity 成员的 Restaurant 对象的 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;
  }

}

让我烦恼的是重复的逻辑(getItemViewType 中的 if/else 和getView 中的switch)。因此,我将实现更改为以下内容:

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

我的问题是:如果不需要,为什么要覆盖这两种方法?

【问题讨论】:

    标签: android android-arrayadapter android-view commonsware


    【解决方案1】:

    如果不需要,为什么要覆盖这两种方法?

    添加几十家不同类型的餐厅,并在滚动时观察您的行回收是否失控,鉴于您的实现如上所示。

    getItemViewType()getViewTypeCount() 是为了确保行回收工作。 Android 将维护单独的对象池,并且只会将正确类型的对象返回给您进行回收。

    在您的解决方案中,您可以对 R.layout.row_delivery 行进行充气,然后在您确实需要 R.layout.row_sit_down 行时将其交还给您进行回收。

    顺便说一句,不要在AdapterView 中使用inflate(R.layout.row_take_out, null)。要正确处理RelativeLayout 规则,请使用inflate(R.layout.row_take_out, parent, false)

    【讨论】:

    • 谢谢马克;我怀疑我的怀疑是由于我对回收缺乏更深入的了解。
    • @ybakos:如果您有 Warescription,请阅读“通过列表获得花式”一章,以更深入地了解回收利用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 2021-02-21
    • 2018-03-14
    • 1970-01-01
    相关资源
    最近更新 更多