为什么菜谱推广覆盖getItemViewType和getViewTypeCount似乎当它不有必要吗?有必要、菜谱、它不、getViewTypeCount

2023-09-06 04:03:52 作者:说散就散

我已经通过Commonsware Android的工作程序设计教程和教程5,加分2,所面临的挑战是使用多布局在根据类型名称的对象一个ListView显示行(一个餐厅的键入属性,它是一个字符串)。因此,它建议覆盖 getItemViewType getViewTypeCount 在自定义ArrayAdapter。此外, Android的文档和其他online 建议相同的配方或博客帖子。

在这种情况下,下面这几招,并覆盖这两种方法能正常工作,但会导致冗余的逻辑基础上检查了餐厅的类型属性的值。例如(请注意,此适配器是一个内部类和餐饮的声明外活动的会员餐厅对象的ArrayList):

 类RestaurantsAdapter扩展ArrayAdapter<餐厅> {

  私有静态最终诠释ROW_TYPE_DELIVERY = 0;
  私有静态最终诠释ROW_TYPE_TAKE_OUT = 1;
  私有静态最终诠释ROW_TYPE_SIT_DOWN = 2;

  RestaurantsAdapter(){
    超(LunchListActivity.this,android.R.layout.simple_list_item_1,餐厅);
  }

  公众诠释getViewTypeCount(){
    返回3;
  }

  公众诠释getItemViewType(INT位置){
    字符串类型= restaurants.get(位置).getType();
    如果(类型==交货){
      返回ROW_TYPE_DELIVERY;
    }否则,如果(类型==take_out){
      返回ROW_TYPE_TAKE_OUT;
    } 其他 {
      返回ROW_TYPE_SIT_DOWN;
    }
  }

  //设置餐厅的视图的图标,名称和地址。
  公共查看getView(INT位置,查看convertView,ViewGroup中父){
    查看排= convertView;
    RestaurantHolder viewHolder;

    如果(行== NULL){
      LayoutInflater充气= getLayoutInflater();
      开关(getItemViewType(位置)){
        案例ROW_TYPE_DELIVERY:
          行= inflater.inflate(R.layout.row_delivery,NULL);
          打破;
        案例ROW_TYPE_TAKE_OUT:
          行= inflater.inflate(R.layout.row_take_out,NULL);
          打破;
        默认:
          行= inflater.inflate(R.layout.row_sit_down,NULL);
          打破;
      }

      viewHolder =新RestaurantHolder(行);
      row.setTag(viewHolder);
    } 其他 {
      viewHolder =(RestaurantHolder)row.getTag();
    }

    viewHolder.populateFrom(restaurants.get(位置));

    返回行;
  }

}
 

我是什么错误重复的逻辑(的if / else在 getItemViewType 开关 getView )。所以,我改变了我的执行以下操作:

 类RestaurantsAdapter扩展ArrayAdapter<餐厅> {

  RestaurantsAdapter(){
    超(LunchListActivity.this,android.R.layout.simple_list_item_1,餐厅);
  }

  //设置餐厅的视图的图标,名称和地址。
  公共查看getView(INT位置,查看convertView,ViewGroup中父){
    查看排= convertView;
    RestaurantHolder viewHolder;

    如果(行== NULL){
      LayoutInflater充气= getLayoutInflater();
      如果(restaurants.get(位置).getType()==交货){
        行= inflater.inflate(R.layout.row_delivery,NULL);
      }否则,如果(restaurants.get(位置).getType()==take_out){
        行= inflater.inflate(R.layout.row_take_out,NULL);
      } 其他 {
        行= inflater.inflate(R.layout.row_sit_down,NULL);
      }
      viewHolder =新RestaurantHolder(行);
      row.setTag(viewHolder);
    } 其他 {
      viewHolder =(RestaurantHolder)row.getTag();
    }

    viewHolder.populateFrom(restaurants.get(位置));

    返回行;
  }

}
 
公共技术点之 View 绘制流程

此完成的动态加载的三个XML布局之一的目标,消除了冗余逻辑,稍微降低的code偶联到布局的数目,并且不需要重写 getViewTypeCount getItemViewType

我的问题是:为什么要重写这两种方法,如果一个人不具备为

? 解决方案   

为什么人应该重写这两种方法,如果一个不就得了?

添加了几十个餐厅,所有不同类型的,并眼睁睁地看着你行回收进入疯狂滚动时,给您的实现如上图所示。

getItemViewType() getViewTypeCount()是确保该行回收工作。 Android将保持独立的对象池,只会交给你行回回收这是正确的类型。

在您的解决方案,你可以抬高一个 R.layout.row_delivery 行,后来把它交还给你回收,当你真正需要的 R.layout.row_sit_down 行。

顺便说一句,不要使用膨胀(R.layout.row_take_out,空)适配器视图。要获得 RelativeLayout的规则,正确处理,使用膨胀(R.layout.row_take_out,父母,FALSE)

I've been working through the Commonsware Android Programming Tutorials and in tutorial 5, extra credit 2, the challenge is to use multiple layouts for displaying rows in a ListView depending on the "type name" of the object (a Restaurant's "type" attribute, which is a String). As such, it suggests overriding getItemViewType and getViewTypeCount in a custom ArrayAdapter. In addition, the android docs and other online recipes or blog posts suggest the same.

In this situation, following this recipe and overriding those two methods works fine but results in redundant logic based on inspecting the value of that Restaurant "type" attribute. For example (note that this adapter is an inner class and restaurants is an ArrayList of Restaurant objects declared as a member of the outer Activity):

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

}

What bugs me is the duplicate logic (the if/else in getItemViewType and the switch in getView). So, I changed my implementation to the following:

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

}

This accomplishes the goal of dynamically loading one of three xml layouts, removes the redundant logic, slightly reduces coupling of code to the number of layouts, and does not require overriding getViewTypeCount and getItemViewType.

My question is: why should one override those two methods if one does not have to?

解决方案

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

Add a few dozen restaurants, all of differing types, and watch as your row recycling goes haywire when you scroll, given your implementation shown above.

getItemViewType() and getViewTypeCount() are to ensure that row recycling works. Android will maintain separate object pools and will only hand you a row back to recycle that is of the correct type.

In your solution, you could inflate a R.layout.row_delivery row, then later get it handed back to you for recycling when you are really in need of a R.layout.row_sit_down row.

BTW, do not use inflate(R.layout.row_take_out, null) in an AdapterView. To get RelativeLayout rules to process correctly, use inflate(R.layout.row_take_out, parent, false).