7

私は Commonsware Android Programming Tutorials に取り組んでおり、チュートリアル 5 の追加クレジット 2 では、オブジェクトの「タイプ名」(レストランの「タイプ」属性) に応じて、ListView に行を表示するために複数のレイアウトを使用することが課題です。 、これは文字列です)。そのため、カスタム ArrayAdapter でオーバーライドすることをgetItemViewTypegetViewTypeCount勧めします。さらに、Android のドキュメントや他のオンライン レシピブログ投稿でも同じことが示唆されています。

この状況では、このレシピに従ってこれら 2 つのメソッドをオーバーライドすると問題なく動作しますが、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;
  }

}

私を悩ませているのは、ロジックの重複です( if/elsegetItemViewTypeswitchin getView)。そこで、実装を次のように変更しました。

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

}

getViewTypeCountこれにより、3 つの xml レイアウトのうちの 1 つを動的にロードするという目標が達成され、冗長なロジックが削除され、コードとレイアウトの数との結合がわずかに減少し、とをオーバーライドする必要がなくなりますgetItemViewType

私の質問は、これらの 2 つのメソッドを上書きする必要がないのに、なぜこれらの 2 つのメソッドを上書きする必要があるのですか?

4

1 に答える 1

16

必要がないのに、なぜこれらの 2 つのメソッドをオーバーライドする必要があるのでしょうか。

数十のレストランをすべて追加し、すべて異なるタイプのレストランを追加し、スクロールすると行のリサイクルがうまくいかないことを確認してください。

getItemViewType()行のgetViewTypeCount()リサイクルが機能することを確認します。Android は個別のオブジェクト プールを維持し、正しい型の行のみをリサイクルに返します。

あなたのソリューションでは、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)

于 2012-04-22T17:20:01.873 に答える