万用适配器(封装通用的基类GeneralAdapter)
2016-10-11 13:26
483 查看
一、万用适配器简介
我们在做Android开发的时候,经常会用到ListView这个控件,我之前写过一篇文章:BaseAdapter与ListView解析。一般来说,我们都会为每一个ListView去建立一个适配器,那这样一个大型项目,不是要建立很多个适配器?!所以,为了提高代码的复用性,我们可以打造一个通用的适配器GeneralAdapter。
二、ViewHolder和GeneralAdapter的编写
一般我们编写Adapter时都会用到ViewHolder,通过convertView.setTag与convertView进行绑定,然后当convertView已经加载过时,直接从与之对于的ViewHolder(getTag)中取得convertView布局中的控件。也就是说,实际上们每个convertView会绑定一个ViewHolder对象,这个viewHolder主要用于帮convertView存储布局中的控件。所以我们只要写出一个通用的ViewHolder,然后对于任意的convertView,提供一个对象让其setTag即可;所以我们使用容器,专门存每个Item布局中的所有控件,而且还要能够查找出来;既然需要查找,那么ListView肯定是不行了,需要一个键值对进行保存,键为控件的Id,值为控件的引用,我们使用比Map效率更高的SparseArray这个类。
以下是ViewHolder类的代码,具体的解释写在代码注释里面:
接下来我们需要的另一个重要的类就是GeneralAdapter。这个通用的Adapter一般需要保持一个List对象,存储一个Bean的集合,不同的ListView,Bean肯定是不同的,这个GeneralAdapter肯定需要支持泛型,内部维持一个List。
GeneralAdapter的代码如下,具体的解释写在代码注释里面:
完成了GeneralAdapter的编写之后,我们再也不需要为每一个ListView编写一个Adapter了,我们只需要在Activity里面使用匿名内部类就行了。
三、万用适配器实例测试
在activity_main里面添加listView控件,然后编写item布局:
接下来,我们只需要在MainActivity中实现ListView和初始化数据就好了(真正做项目开发的时候,为了降低代码的耦合度,还是建议遵循一定的设计模式,不要将数据的处理写在Activity里面,这里只是做个测试)
最终实现的效果图还是和上一篇文章一样:
这样一来,代码量是不是简化了不少呢?
我们在做Android开发的时候,经常会用到ListView这个控件,我之前写过一篇文章:BaseAdapter与ListView解析。一般来说,我们都会为每一个ListView去建立一个适配器,那这样一个大型项目,不是要建立很多个适配器?!所以,为了提高代码的复用性,我们可以打造一个通用的适配器GeneralAdapter。
二、ViewHolder和GeneralAdapter的编写
一般我们编写Adapter时都会用到ViewHolder,通过convertView.setTag与convertView进行绑定,然后当convertView已经加载过时,直接从与之对于的ViewHolder(getTag)中取得convertView布局中的控件。也就是说,实际上们每个convertView会绑定一个ViewHolder对象,这个viewHolder主要用于帮convertView存储布局中的控件。所以我们只要写出一个通用的ViewHolder,然后对于任意的convertView,提供一个对象让其setTag即可;所以我们使用容器,专门存每个Item布局中的所有控件,而且还要能够查找出来;既然需要查找,那么ListView肯定是不行了,需要一个键值对进行保存,键为控件的Id,值为控件的引用,我们使用比Map效率更高的SparseArray这个类。
以下是ViewHolder类的代码,具体的解释写在代码注释里面:
/** * Created by ZYQ on 2016/10/14. * 一个通用的ViewHolder类 */ public class ViewHolder { // 使用了SparseArray<View>用于存储与之对于的convertView的所有的控件 private SparseArray<View> mViews; private int mPosition; private View mConvertView; public ViewHolder(Context context, ViewGroup parent, int layoutID, int position) { this.mPosition = position; this.mViews = new SparseArray<View>(); mConvertView = LayoutInflater.from(context).inflate(layoutID, parent, false); mConvertView.setTag(this); } // 拿到一个ViewHolder对象 public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutID, int position) { if (convertView == null) { return new ViewHolder(context, parent, layoutID, position); } else { ViewHolder holder = (ViewHolder) convertView.getTag(); holder.mPosition = position; return holder; } } /** * 使用泛型T,返回值是View的一个子类 * 通过viewID来获取控件 * 如果没有则将控件添加到SparseArray容器中 */ public <T extends View> T getView(int viewID) { View view = mViews.get(viewID); if (view == null) { view = mConvertView.findViewById(viewID); mViews.put(viewID, view); } return (T) view; } public View getmConvertView() { return mConvertView; } /** * 封装setText方法 * 通过getView获得并设置TextView的值 */ public ViewHolder setText(int viewID, String text) { TextView tv = getView(viewID); tv.setText(text); return this; } /** * 封装setImage方法 * 通过getView获得并设置ImageView的图片 */ public ViewHolder setImage(int viewID, int imageResID) { ImageView imageView = getView(viewID); imageView.setImageResource(imageResID); return this; } }
接下来我们需要的另一个重要的类就是GeneralAdapter。这个通用的Adapter一般需要保持一个List对象,存储一个Bean的集合,不同的ListView,Bean肯定是不同的,这个GeneralAdapter肯定需要支持泛型,内部维持一个List。
GeneralAdapter的代码如下,具体的解释写在代码注释里面:
/** * Created by ZYQ on 2016/10/15. * 将GeneralAdapter写成任何适配器的抽象基类 * 只有getView()中的convert方法是需要子类去实现的 */ public abstract class GeneralAdapter<T> extends BaseAdapter { // 使用泛型<T>可以装载多种Bean类型 protected List<T> mDatas; protected Context mContext; protected LayoutInflater mInflater; protected int mLayoutID; public GeneralAdapter(Context context, List<T> datas, int layoutID) { this.mContext = context; this.mDatas = datas; mInflater = LayoutInflater.from(context); this.mLayoutID = layoutID; } @Override public int getCount() { return mDatas.size(); } @Override public T getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // 实例化一个viewHolder ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent, mLayoutID, position); convert(viewHolder, getItem(position)); return viewHolder.getmConvertView(); } // 对外公布的convert方法,并将holder和Bean对象传出去 public abstract void convert(ViewHolder holder, T t); }
完成了GeneralAdapter的编写之后,我们再也不需要为每一个ListView编写一个Adapter了,我们只需要在Activity里面使用匿名内部类就行了。
三、万用适配器实例测试
在activity_main里面添加listView控件,然后编写item布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imageView" android:layout_width="60dp" android:layout_height="60dp" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="30dp" android:text="Title" android:layout_toEndOf="@+id/imageView" android:gravity="center" android:textSize="25sp"/> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="30dp" android:text="Content what what what what" android:layout_toEndOf="@+id/imageView" android:layout_below="@id/tv_title" android:gravity="center_vertical" android:textSize="20sp"/> </RelativeLayout>
接下来,我们只需要在MainActivity中实现ListView和初始化数据就好了(真正做项目开发的时候,为了降低代码的耦合度,还是建议遵循一定的设计模式,不要将数据的处理写在Activity里面,这里只是做个测试)
public class MainActivity extends AppCompatActivity { private List<ItemBean> mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initDatas(); initView(); } private void initDatas() { mDatas = new ArrayList<ItemBean>(); for (int i = 0; i < 20; i++) { mDatas.add(new ItemBean( R.mipmap.ic_launcher, "标题", "我是正文 我是正文 我是正文")); } } private void initView() { ListView mListView = (ListView) findViewById(R.id.listview_main); if (mListView != null) { // 使用匿名内部类简化代码 mListView.setAdapter(new GeneralAdapter<ItemBean>(MainActivity.this, mDatas, R.layout.item) { @Override public void convert(ViewHolder holder, ItemBean itemBean) { // 使用链式编程 holder.setImage(R.id.imageView, R.mipmap.ic_launcher) .setText(R.id.tv_title, itemBean.getItemTitle()) .setText(R.id.tv_content, itemBean.getItemContent()); } }); } } }
最终实现的效果图还是和上一篇文章一样:
这样一来,代码量是不是简化了不少呢?
The end! 。◕‿◕。
相关文章推荐
- 基类适配器封装
- RecyclerView的通用适配器,和滚动时不加载图片的封装
- RecyclerView通用适配器Adapter,对Adapter的封装
- RxAndroid+Retrofit+GreenDao+MVP框架---通用基类封装(三)
- java网站建设6-封装Springjdbc的通用基类
- RecyclerView的通用适配器,和滚动时不加载图片的封装
- RecyclerView的通用适配器,和滚动时不加载图片的封装
- RecyclerView的通用适配器,和滚动时不加载图片的封装
- RxAndroid+Retrofit+GreenDao+MVP框架---通用基类封装(一)
- RxAndroid+Retrofit+GreenDao+MVP框架---通用基类封装(二)
- android通用适配器的封装
- RecyclerView的通用适配器,和滚动时不加载图片的封装
- 封装Springjdbc的通用基类(copy)
- 使用redisTemplete简单封装的一个通用操作类
- Mysql通用查询方法(采用泛型确定输入类型,BeanUtils进行对象封装)
- iOS通用库--常用功能一之与时间和日历相关的封装
- 对进度条的通用封装实现
- Activity,Fragment的基类封装,简化findViewById,Fragment懒加载和不重复加载等
- iOS数据库离线缓存思路和网络层封装——网络请求基类封装
- 基类RecyclerViewAdapter以及BaseViewHolder。减少适配器的重复代码量