[关闭]
@kmfish 2015-09-16T13:06:18.000000Z 字数 5875 阅读 3380

MultiTypeListViewAdapter Android ListView 多type的Adapter封装

Android ListView Adapter ViewType


MultiTypeListViewAdapter 是什么?

MultiTypeListViewAdapter,顾名思义。其封装了多type下的Adapter的编程模式,通过对每种type统一接口,利用多态的方式,将type的实现从Adapter中抽离出来。Adapter只需面向统一接口,所以可以提供一个通用实现,实现代码不再变动。而会变动的每个type对应的item实现,则由使用者自己去实现。对扩展开放,对修改封闭。

同时,由于每个type的item均被抽离出来了。相当于复用的粒度为每个type item,可以根据需要,动态地选择合适的item去添加到adapter中。提高了代码复用,每个人编写维护好自己的item即可,避免了多人合作时都去修改Adapter,容易造成冲突。

另外,由于ViewHolder 模式的规范,MultiTypeListViewAdapter也同时封装了ViewHolder模式。


常见的ListView Adapter 实现

先看一下常见的ListAdapter 实现,分为单个type和多type两种情况。

1、单Type的Adapter

  1. class ListAdapter extend BaseAdapter {
  2. ...
  3. private List<String> contents = new ArrayList();
  4. ...
  5. public View getView(int position, View convertView, ViewGroup parent) {
  6. String item = getItem(position);
  7. if(null == item) {
  8. throw new RuntimeException("list item is never null. pos:" + position);
  9. } else {
  10. ViewHolder holder;
  11. if(null == convertView) {
  12. holder = createViewHolder(parent);
  13. convertView = holder.itemView;
  14. convertView.setTag(holder);
  15. } else {
  16. holder = (ViewHolder)convertView.getTag();
  17. }
  18. item.updateHolder(holder, position);
  19. return convertView;
  20. }
  21. }
  22. }
  23. private ViewHolder createViewHolder(ViewGroup parent) {
  24. // create item view from layout xml
  25. View itemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item1, parent, false);
  26. ViewHolder holder = new ViewHolder(itemView);
  27. return holder;
  28. }
  29. private void updateHolder(ViewHolder holder, String item) {
  30. // update item view
  31. holder.text.setText(item);
  32. }
  33. private class ViewHolder {
  34. TextView text;
  35. ViewHolder(View itemView) {
  36. text = (TextView)itemView.findViewById(R.id.text);
  37. }
  38. }
  39. ...
  40. }

应该是挺常见的写法吧,继续往下。

2、多type的adapter

  1. class ListAdapter extend BaseAdapter {
  2. ...
  3. private List<String> contents = new ArrayList();
  4. ...
  5. public int getItemViewType(int position) {
  6. if (position % 2 == 0) {
  7. return 0;
  8. }
  9. return 1;
  10. }
  11. public int getViewTypeCount() {
  12. return 2;
  13. }
  14. public View getView(int position, View convertView, ViewGroup parent) {
  15. String item = getItem(position);
  16. if(null == item) {
  17. throw new RuntimeException("list item is never null. pos:" + position);
  18. } else {
  19. ViewHolder holder;
  20. if(null == convertView) {
  21. if (getItemViewType(position) == 0) {
  22. holder = createViewHolder(parent);
  23. } else if (getItemViewType(position) == 1) {
  24. holder = createViewHolder1(parent);
  25. }
  26. convertView = holder.itemView;
  27. convertView.setTag(holder);
  28. } else {
  29. holder = (ViewHolder)convertView.getTag();
  30. }
  31. if (getItemViewType(position) == 0) {
  32. item.updateHolder(holder, position);
  33. } else if (getItemViewType(position) == 1) {
  34. item.updateHolder1(holder, position);
  35. }
  36. return convertView;
  37. }
  38. }
  39. }
  40. private ViewHolder createViewHolder(ViewGroup parent) {
  41. // create item view from layout xml
  42. View itemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item1, parent, false);
  43. ViewHolder holder = new ViewHolder(itemView);
  44. return holder;
  45. }
  46. private ViewHolder createViewHolder1(ViewGroup parent) {
  47. // create item view from layout xml
  48. View itemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item2, parent, false);
  49. ViewHolder holder = new ViewHolder(itemView);
  50. return holder;
  51. }
  52. private void updateHolder(ViewHolder holder, String item) {
  53. // update item view
  54. holder.text.setText(item);
  55. }
  56. private void updateHolder1(ViewHolder1 holder, String item) {
  57. // update item view
  58. holder.text.setText(item);
  59. holder.img.setImageResoure(R.drawable.img);
  60. }
  61. private class ViewHolder {
  62. TextView text;
  63. ViewHolder(View itemView) {
  64. text = (TextView)itemView.findViewById(R.id.text);
  65. }
  66. }
  67. private class ViewHolder1 {
  68. TextView text;
  69. ImageView img;
  70. ViewHolder(View itemView) {
  71. text = (TextView)itemView.findViewById(R.id.text);
  72. img = (ImageView)itemView.findViewById(R.id.img);
  73. }
  74. }
  75. ...
  76. }

看到这里,是否感觉这个Adapter的getView()开始有些让人不舒服了呢。若type再进一步增加,难不成还得继续if/else下去,adapter变得又臭又长。估计往后下去,就再没人愿意维护了。而且,这个Adapter的这一堆代码还得到处重复写下去,每个有listView的地方,都得配套一个adapter。针对这个坑,我设计了MultiTypeListViewAdapter来解决。希望能帮助到有需要的程序猿们~


使用 MultiTypeListViewAdapter

  1. public class MainActivity extends AppCompatActivity {
  2. private ListView listView;
  3. private MultiTypeArrayAdapter adapter;
  4. private static final int ITEM_TYPE_1 = 0;
  5. private static final int ITEM_TYPE_2 = 1;
  6. private static final int ITEM_TYPE_COUNT = 2;
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_main);
  11. listView = (ListView) findViewById(R.id.listview);
  12. adapter = new MultiTypeArrayAdapter(ITEM_TYPE_COUNT);
  13. listView.setAdapter(adapter);
  14. setupAdapter();
  15. }
  16. private void setupAdapter() {
  17. adapter.setTypeCount(ITEM_TYPE_COUNT);
  18. LineListItem1 item1 = new LineListItem1(this, ITEM_TYPE_1, "line type 1");
  19. LineListItem2 item2 = new LineListItem2(this, ITEM_TYPE_2, "line type 2");
  20. adapter.setNotifyOnChange(false);
  21. for (int i = 0, len = 50; i < len; i++) {
  22. adapter.addItem( i % 2 == 0 ? item1 : item2);
  23. }
  24. adapter.notifyDataSetChanged();
  25. }
  26. }
  27. public class LineListItem1 extends BaseListItem {
  28. private String line;
  29. public LineListItem1(Context mContext, int viewType, String line) {
  30. super(mContext, viewType);
  31. this.line = line;
  32. }
  33. @Override
  34. protected int onGetItemLayoutRes() {
  35. return R.layout.list_item1;
  36. }
  37. @Override
  38. protected ViewHolder onCreateViewHolder(View itemView) {
  39. return new LineViewHolder(itemView);
  40. }
  41. @Override
  42. public void updateHolder(ViewHolder holder, int pos) {
  43. LineViewHolder h = (LineViewHolder) holder;
  44. h.text.setText(line + "_" + pos);
  45. }
  46. private class LineViewHolder extends ViewHolder {
  47. TextView text;
  48. public LineViewHolder(View itemView) {
  49. super(itemView);
  50. text = (TextView) itemView.findViewById(R.id.line_text);
  51. }
  52. }
  53. }
  54. public class LineListItem2 extends BaseListItem {
  55. private String line;
  56. public LineListItem2(Context mContext, int viewType, String line) {
  57. super(mContext, viewType);
  58. this.line = line;
  59. }
  60. @Override
  61. protected int onGetItemLayoutRes() {
  62. return R.layout.list_item2;
  63. }
  64. @Override
  65. protected ViewHolder onCreateViewHolder(View itemView) {
  66. return new LineViewHolder2(itemView);
  67. }
  68. @Override
  69. public void updateHolder(ViewHolder holder, int pos) {
  70. LineViewHolder2 h = (LineViewHolder2) holder;
  71. h.text.setText(line + "_" + pos);
  72. h.img.setImageResource(R.drawable.icon_git);
  73. }
  74. private class LineViewHolder2 extends ViewHolder {
  75. ImageView img;
  76. TextView text;
  77. public LineViewHolder2(View itemView) {
  78. super(itemView);
  79. img = (ImageView) itemView.findViewById(R.id.thumb);
  80. text = (TextView) itemView.findViewById(R.id.name);
  81. }
  82. }
  83. }

可以看到,使用MultiTypeListViewAdapter之后,实现多type的Adapter变得相当简单了。再也不用面对一堆判断itemType的if/else了。每增加一种type,只需增加一种新的ListItem即可,再也不用去改动Adapter的代码了。

项目发布在github上了,MultiTypeListViewAdapter,欢迎fork和交流。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注