Android 自定义 BaseAdapter 最佳实践-阿里云开发者社区

开发者社区> 玄学酱> 正文

Android 自定义 BaseAdapter 最佳实践

简介:
+关注继续查看

虽然现在很多新的项目都在使用RecyclerView,但是很多开发者在一些场景中还是倾向使用ListView或者GridView,然后就是需要写许多的Adapter。一次项目组在新启动一个新项目的时候,有个同事拿来了一个网上说的万能Adapter,在使用的时候发现即使在单个视图类型一旦逻辑判断比较复杂情况下非常不方便,更不用说在适配器Adapter中使用多视图类型了,这里仅是个人观点,也许没有掌握到精华。

当然了随着RecyclerView的使用,网上也有很多有关对RecyclerView多视图类型Adapter封装的博客,MultiType 3.0是一个大神写的比较全面的Adapter,万能适配器Adapter自己使用不是很方便,于是就参看RecyclerView中Adapter的实现方式进行对BaseAdapter进行了简单的封装,封装的目一是为了少写代码,另外一个就是让逻辑看上去更清晰一些。我们知道在RecyclerView的Adapter实现中它将视图创建与数据绑定进行了分离,同时将对View的查找创建也剥离开来了,本文就主要介绍如何将BaseAdapter的使用封装为跟RecyclerView的Adapter使用方式一致。由于很多时候在Adapter中我们都是使用的简单的视图类型,即单类型视图,因此本文将单视图类型的Adapter单独封装了一下,比使用多视图类型的Adapter使用了更严格的数据类型检查,同时在使用上也方便了许多。

RecyclerView中Adapter的使用

在使用RecyclerView的Adapter的时候我们首先需要继承RecyclerView的一个静态内部类Adapter,然后重写三个方法,实际上下面三个方法是必须要重写的,因为都是抽象方法。

  • getItemCount()
  • onBindViewHolder(VH holder, int position)
  • onCreateViewHolder(ViewGroup parent, int viewType)

一般情况下重写上面三个方法就可以,但是如果存在多视图类型,在第三个方法

onCreateViewHolder()方法中我们也可以看到有一个参数是viewType,该参数作用就是针对不同的viewType需要创建不同的ViewHolder,因此还需要重写一个方法getItemViewType(int position),针对多视图类型同BaseAdapter实现方式倒是很像,在BaseAdapter中这是需要除此之外还要重写一个方法getViewTypeCount(),但是在RecyclerView的Adapter中不需要该方法。

简单类型Adapter


  1. private class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { 
  2.  
  3.     @Override 
  4.     public int getItemCount() { 
  5.         return COUNT
  6.     } 
  7.  
  8.     @Override 
  9.     public void onBindViewHolder(MyViewHolder holder, int position) { 
  10.         holder.textView.setText("TEXT_" + position); 
  11.     } 
  12.  
  13.     @Override 
  14.     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
  15.         View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_text, parent, false); 
  16.         MyViewHolder holder = new MyViewHolder(view); 
  17.         return holder; 
  18.     } 
  19.  
  20.  
  21. private static class MyViewHolder extends RecyclerView.ViewHolder { 
  22.     private TextView textView; 
  23.  
  24.     public MyViewHolder(View itemView) { 
  25.         super(itemView); 
  26.         textView = (TextView) itemView.findViewById(R.id.textView); 
  27.     } 

复杂类型Adapter


  1. private class MyAdapter extends RecyclerView.Adapter<ViewHolder> { 
  2.  
  3.     @Override 
  4.     public int getItemCount() { 
  5.         return COUNT
  6.     } 
  7.  
  8.     @Override 
  9.     public int getItemViewType(int position) { 
  10.         return position % 2 == 0 ? TYPE_IMAGE : TYPE_TEXT; 
  11.     } 
  12.  
  13.     @Override 
  14.     public void onBindViewHolder(ViewHolder holder, int position) { 
  15.         int type = getItemViewType(position); 
  16.         switch (type) { 
  17.         case TYPE_TEXT: 
  18.             ((MyTextHolder) holder).textView.setText("TEXT_" + position); 
  19.             break; 
  20.         case TYPE_IMAGE: 
  21.             ((MyImageHolder) holder).imageView.setImageResource(R.drawable.image); 
  22.             break; 
  23.         } 
  24.     } 
  25.  
  26.     @Override 
  27.     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
  28.         View view
  29.         ViewHolder holder = null
  30.         switch (viewType) { 
  31.         case TYPE_TEXT: 
  32.             view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_text, parent, false); 
  33.             holder = new MyTextHolder(view); 
  34.             break; 
  35.         case TYPE_IMAGE: 
  36.             view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_image, parent, false); 
  37.             holder = new MyImageHolder(view); 
  38.             break; 
  39.         } 
  40.         return holder; 
  41.     } 
  42.  
  43. private class MyTextHolder extends RecyclerView.ViewHolder { 
  44.     private TextView textView; 
  45.  
  46.     public MyTextHolder(View itemView) { 
  47.         super(itemView); 
  48.         textView = (TextView) itemView.findViewById(R.id.textView); 
  49.     } 
  50.  
  51. private class MyImageHolder extends ViewHolder { 
  52.     private ImageView imageView; 
  53.  
  54.     public MyImageHolder(View itemView) { 
  55.         super(itemView); 
  56.         imageView = (ImageView) itemView.findViewById(R.id.imageView); 
  57.     } 

自定义BaseAdapter

在自定义基类之前,先简单分析一下,我们需要自定义一个支持单种视图的Adapter,还要自定义一个支持多种视图类型的Adapter,两个类都要继承BaseAdapter,先将两个类都公用的部分抽取出来定义为MyAdapter。


  1. public abstract class MyAdapter<T> extends BaseAdapter { 
  2.  
  3.     protected List<T> dataList = new ArrayList<>(); 
  4.     protected Context context; 
  5.     protected LayoutInflater inflater; 
  6.  
  7.     public MyAdapter(Context context) { 
  8.         this.context = context; 
  9.         inflater = LayoutInflater.from(context); 
  10.     } 
  11.  
  12.     public void setDataList(List<T> dataList) { 
  13.         this.dataList = dataList; 
  14.         notifyDataSetChanged(); 
  15.     } 
  16.  
  17.     @Override 
  18.     public int getCount() { 
  19.         if (null == dataList) { 
  20.             return 0; 
  21.         } 
  22.         return dataList.size(); 
  23.     } 
  24.  
  25.     @Override 
  26.     public T getItem(int position) { 
  27.         return dataList.get(position); 
  28.     } 
  29.  
  30.     @Override 
  31.     public long getItemId(int position) { 
  32.         return position; 
  33.     } 
  34.  

在RecyclerView的Adapter实现中是没有getView()方法的,下面我们就分析一下getView()方法如何拆分,一般情况下我们在实现getView()方法都是如下流程。


  1. public View getView(int position, View convertView, ViewGroup parent) { 
  2.     ViewHolder holder = null
  3.     if (null == convertView) { 
  4.         //填充布局 
  5.         convertView=inflater.inflate(R.layout.item_layout, parent,false); 
  6.         holder = new ViewHolder(); 
  7.         //通过ID查询控件 
  8.         holder.textView=(TextView)convertView.findViewById(R.id.textView); 
  9.         holder.imageView=(ImageView)convertView.findViewById(R.id.imageView); 
  10.         convertView .setTag(holder); 
  11.     } else { 
  12.         holder = (ViewHolder) convertView.getTag(); 
  13.     } 
  14.     //赋值逻辑 
  15.     return convertView; 
  16. //一个空的ViewHolder 
  17. public static class ViewHolder{ 
  18.     TextView textView; 
  19.     ImageView imageView; 

Java编程比较流行的一种编程方式不是说面向接口编程吗,在Android开发中也有一个开发方式叫做面向Holder的编程,上面代码是传统的实现ViewHolder的方式,说句实现话就没做什么事,就是作为一个载体承载着我们需要的控件。我们让ViewHolder多做一些事情,让它在convertView==null情况下需要做的多数逻辑都放到ViewHolder中去。


  1. public class ViewHolder { 
  2.     private final View itemView; 
  3.  
  4.     public ViewHolder(View itemView) { 
  5.         if (null == itemView) { 
  6.             throw new IllegalArgumentException("itemView must not be null"); 
  7.         } else { 
  8.             this.itemView = itemView; 
  9.             itemView.setTag(this); 
  10.         } 
  11.     } 
  12.  
  13.     public View getItemView() { 
  14.         return itemView; 
  15.     } 

在ViewHolder中的itemView就是getView()方法中的convertView,这里刚好是条目的根View,类似RecyclerView中ViewHolder构造方法中itemView。由于不同的视图需要创建不同的ViewHolder,因此我们可以将创建ViewHolder的方法设置为抽象的方法暴露出去,另外赋值的时候我们也需要根据具体的业务进行赋值,同样设置一个抽象方法。


  1. public abstract class SimpleAdapter<T,VH extends ViewHolder> extends MyAdapter<T> { 
  2.  
  3.     public SimpleAdapter(Context context) { 
  4.         super(context); 
  5.     } 
  6.  
  7.     public View getView(int position, View convertView, ViewGroup parent) { 
  8.         VH holder = null
  9.         if (null == convertView) { 
  10.             holder = onCreateViewHolder(parent); 
  11.             convertView = holder.getItemView(); 
  12.         } else { 
  13.             holder = (VH) convertView.getTag(); 
  14.         } 
  15.         onBindViewHolder(holder, position); 
  16.         return convertView; 
  17.     } 
  18.  
  19.     public abstract void onBindViewHolder(VH holder, int position); 
  20.  
  21.     public abstract VH onCreateViewHolder(ViewGroup parent); 
  22.  

在设置多视图类型的Adapter的时候只需要在创建ViewHolder的时候多传入一个viewType的参数即可。


  1. public abstract class MultiAdapter<T> extends MyAdapter<T> { 
  2.  
  3.     public MultiAdapter(Context context) { 
  4.         super(context); 
  5.     } 
  6.  
  7.     @Override 
  8.     public View getView(int position, View convertView, ViewGroup parent) { 
  9.         ViewHolder holder = null
  10.         if (null == convertView) { 
  11.             holder = onCreateViewHolder(parent, getItemViewType(position)); 
  12.             convertView = holder.getItemView(); 
  13.         } else { 
  14.             holder = (ViewHolder) convertView.getTag(); 
  15.         } 
  16.         onBindViewHolder(holder, position); 
  17.         return convertView; 
  18.     } 
  19.  
  20.     public abstract void onBindViewHolder(ViewHolder holder, int position); 
  21.  
  22.     public abstract ViewHolder onCreateViewHolder(ViewGroup parent, int viewType); 
  23.  

自定义BaseAdapter的使用

单视图类型SimpleAdapter使用


  1. public class TextAdapter extends SimpleAdapter<String, TextAdapter.TextHolder> { 
  2.  
  3.     public TextAdapter(Context context) { 
  4.         super(context); 
  5.     } 
  6.  
  7.     @Override 
  8.     public void onBindViewHolder(TextHolder holder, int position) { 
  9.         holder.textView.setText(getItem(position)); 
  10.     } 
  11.  
  12.     @Override 
  13.     public TextHolder onCreateViewHolder(ViewGroup parent) { 
  14.         View convertView=inflater.inflate(R.layout.item_text, parent, false); 
  15.         return new TextHolder(convertView); 
  16.     } 
  17.  
  18.     static class TextHolder extends ViewHolder{ 
  19.  
  20.         public TextView textView; 
  21.  
  22.         public TextHolder(View itemView) { 
  23.             super(itemView); 
  24.             textView=(TextView) itemView.findViewById(R.id.textView); 
  25.         } 
  26.     } 

这里我们使用了两个泛型,一个是ViewHolder中支持的数据类型String,另外一个就是我们需要创建的ViewHolder,这样在onCreateViewHolder方法的返回值就会自动返回我们自定义的ViewHolder,有关泛型更多的知识可以参看Java泛型使用解析,单视图类型Adapter的使用比RecyclerView的Adapter还要方便许多。

多视图类型的使用


  1. public class RichAdapter extends MultiAdapter<String> { 
  2.  
  3.     private static final int TEXT = 0; 
  4.     private static final int PIC = 1; 
  5.  
  6.     public RichAdapter(Context context) { 
  7.         super(context); 
  8.     } 
  9.  
  10.     @Override 
  11.     public int getViewTypeCount() { 
  12.         return 2; 
  13.     } 
  14.  
  15.     @Override 
  16.     public int getItemViewType(int position) { 
  17.         if (position % 3 == 0) { 
  18.             return PIC; 
  19.         } else { 
  20.             return TEXT; 
  21.         } 
  22.     } 
  23.  
  24.     @Override 
  25.     public void onBindViewHolder(ViewHolder holder, int position) { 
  26.         switch (getItemViewType(position)) { 
  27.         case TEXT: 
  28.             TextHolder textHolder=(TextHolder) holder; 
  29.             textHolder.textView.setText(getItem(position)); 
  30.             break; 
  31.         case PIC: 
  32.             ImageHolder imageHolder=(ImageHolder) holder; 
  33.             imageHolder.imageView.setImageResource(R.drawable.image); 
  34.             break; 
  35.         } 
  36.     } 
  37.  
  38.     @Override 
  39.     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
  40.         View itemView = null
  41.         ViewHolder holder = null
  42.         switch (viewType) { 
  43.         case TEXT: 
  44.             itemView = inflater.inflate(R.layout.item_text, parent, false); 
  45.             holder = new TextHolder(itemView); 
  46.             break; 
  47.         case PIC: 
  48.             itemView = inflater.inflate(R.layout.item_image, parent, false); 
  49.             holder = new ImageHolder(itemView); 
  50.             break; 
  51.         } 
  52.         return holder; 
  53.     } 
  54.  
  55.     private static class TextHolder extends ViewHolder { 
  56.         TextView textView; 
  57.  
  58.         public TextHolder(View itemView) { 
  59.             super(itemView); 
  60.             textView = (TextView) itemView.findViewById(R.id.textView); 
  61.         } 
  62.  
  63.     } 
  64.  
  65.     private static class ImageHolder extends ViewHolder { 
  66.         ImageView imageView; 
  67.  
  68.         public ImageHolder(View itemView) { 
  69.             super(itemView); 
  70.             imageView = (ImageView) itemView.findViewById(R.id.imageView); 
  71.         } 
  72.     } 

这里的使用情况跟RecyclerView的使用几乎是一模一样,唯一不一样的地方就是多写了一个getViewTypeCount()方法,在ListView或者GridView使用BaseAdapter实现多种类型视图的时候该方法必须要重写。





本文作者:佚名
来源:51CTO

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Android官方开发文档Training系列课程中文版:动画视图之创建自定义转场动画
原文地址:http://android.xsoftlab.net/training/transitions/custom-transitions.html 自定义转场可以创建自定义动画。
943 0
Dataset之MNIST:自定义函数mnist.load_mnist根据网址下载mnist数据集(四个ubyte.gz格式数据集文件)
Dataset之MNIST:自定义函数mnist.load_mnist根据网址下载mnist数据集(四个ubyte.gz格式数据集文件)
6 0
广播的最佳实践——实现强制下线功能(Android_Broadcast)
 关键词:Broadcast, 生命周期,继承 本项目基本思路: 1.先创建一个ActivityCollector类用于管理所有的活动; 2.然后创建一个BaseActivity类作为所有活动的父类: 父类功能有二: 其一,用于辅助统筹管理本项目的所有活动。
581 0
开源最佳实践:Android平台页面路由框架ARouter
为了更好地让开发者们更加深入了解阿里开源,阿里云云栖社区在3月1号了举办“阿里开源项目最佳实践”在线技术峰会,直播讲述了当前阿里新兴和经典开源项目实战经验以及背后的开发思路,在本次在线技术峰会上,阿里云资深开发工程师刘志龙分享了Android平台页面路由框架ARouter的技术方案、解决的问题以及在实际场景中的最佳实践。
43329 0
给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler
    写自定义控件已经好久了,也有几个用得时间比较长的,但是对于“事件”一直是比较模糊,没有很详细的理解。          最近升级分页控件,由于原来使用的是VB.net(在VB.net里面添加一个事件是比较容易的),现在想改用C#,而原来的方法又写得比较笨拙,想换一个更简洁一点的方法,所以不得不重新认识一下事件。
681 0
手把手教你完成MaxCompute JDBC自定义日志配置
本文讲述了如何在MaxCompute JDBC 2.0 beta版本中完成日志功能的相关配置,并进一步对logback的配置文件进行了示例及说明。
5052 0
【黑金ZYNQ7000系列原创视频教程】07.自定义IP&mdash;&mdash;定制RTC IP实验
黑金论坛地址: http://www.heijin.org/forum.php?mod=viewthread&tid=36641&extra=page%3D1   爱奇艺地址: http://www.iqiyi.com/w_19ruggkqf9.html?source=
1094 0
《深入理解Android:Telephony原理剖析与最佳实践》一导读
目前国内市场上针对Android的书籍很多,但这些书籍中,绝大多数是基于Android SDK在应用层的开发进行讲解的。针对Android系统级的源代码分析的书籍,主要是邓凡平著的《深入理解Android:卷Ⅰ》和《深入理解Android:卷Ⅱ》,但深入理解Android Telephony的书籍国内目前还是空白。
1053 0
QuickPager asp.net 分页控件、表单控件等自定义控件下载 和介绍 【2009.09.07更新】
  最新下载地址: 自然框架的源代码、Demo、数据库、配置信息管理程序下载(2010.01.25更新)     QuickControl web控件集包含的控件 QuickControl web控件集——基本控件: 控件名称 说明 详细介绍 MyTextBox ...
949 0
+关注
玄学酱
这个时候,玄酱是不是应该说点什么...
17436
文章
438
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载