¿Por qué las recetas promueven sobreescribir getItemViewType y getViewTypeCount cuando no parece necesario?

He estado trabajando a través de los Tutoriales de Programación Android de Commonsware y en el tutorial 5, el crédito adicional 2, el desafío es utilizar múltiples diseños para mostrar las filas en un ListView dependiendo del "nombre de tipo" del objeto , Que es una cadena). Como tal, sugiere sobreescribir getItemViewType y getViewTypeCount en un ArrayAdapter personalizado. Además, los documentos android y otras recetas en línea o blogs sugieren lo mismo.

En esta situación, seguir esta receta y reemplazar esos dos métodos funciona bien, pero resulta en una lógica redundante basada en inspeccionar el valor de ese atributo "tipo" de Restaurante. Por ejemplo (tenga en cuenta que este adaptador es una clase interna y restaurants es un ArrayList de objetos de restaurante declarado como un miembro de la actividad exterior):

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

Lo que me fastidia es la lógica duplicada (if / else en getItemViewType y el switch en getView ). Por lo tanto, cambié mi implementación a la siguiente:

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

Esto logra el objetivo de cargar dinámicamente uno de los tres diseños xml, elimina la lógica redundante, reduce ligeramente el acoplamiento del código al número de diseños y no requiere superar getViewTypeCount y getItemViewType .

Mi pregunta es: ¿por qué uno debe anular esos dos métodos si uno no tiene que hacerlo?

¿Por qué debería uno anular esos dos métodos si uno no tiene que?

Añadir una docena de restaurantes, todos de diferentes tipos, y ver como su reciclado de la fila se vuelve loco cuando se desplaza, dada su aplicación mostrada anteriormente.

getItemViewType() y getViewTypeCount() garantizan que el reciclaje de filas funcione. Android mantendrá distintas agrupaciones de objetos y solo te entregará una fila para reciclar que sea del tipo correcto.

En su solución, podría inflar una fila R.layout.row_delivery , a continuación, R.layout.row_delivery a devolverle para reciclarla cuando realmente necesite una fila R.layout.row_sit_down .

BTW, no utilice inflate(R.layout.row_take_out, null) en un AdapterView . Para que las reglas RelativeLayout procesen correctamente, utilice inflate(R.layout.row_take_out, parent, false) .

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.