android – 为什么配方在没有必要时会提升覆盖getItemViewType和getViewTypeCount?

我一直在使用Commonsware Android编程教程,在教程5中,额外的功劳2,挑战是使用多个布局在ListView中显示行,具体取决于对象的“类型名称”(餐厅的“类型”属性,这是一个字符串).因此,它建议在自定义ArrayAdapter中覆盖getItemViewType和getViewTypeCount.此外,android docs和其他 online recipesblog posts建议相同.

在这种情况下,遵循此配方并覆盖这两种方法可以正常工作,但会导致基于检查该Restaurant“type”属性值的冗余逻辑.例如(请注意,此适配器是内部类,而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中的开关).所以,我将实现改为以下内容

class RestaurantsAdapter extends ArrayAdapter<Restaurant> {

  RestaurantsAdapter() {
    super(LunchListActivity.this,restaurants);
  }

  // Sets the icon,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布局之一,删除冗余逻辑,略微减少代码与布局数量的耦合,并且不需要重写getViewTypeCount和getItemViewType的目标.

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

解决方法

why should one override those two methods if one does not have to?

添加几十家不同类型的餐馆,并观看您的滚动时行回收会变得混乱,如上所示.

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

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...