Why do recipes promote overriding getItemViewType and getViewTypeCount when it doesn't seem necessary?
android, android-arrayadapter, android-view, commonsware
Solution
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)`.
Problem
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?