Android 一起来封装一个简单易用的Adapter
来源:互联网 发布:深入浅出python豆瓣 编辑:程序博客网 时间:2024/05/26 02:52
前言
还记得我初学 Android 没多久又需要用到 ListView 的时候还不会写 Adapter,结果我居然硬生生的用 TableLayout 和 LinearLayout 把 ListView 给替代了。现在回过神了想想,我当时还真是厉害啊,在另一种意义上
其实要会写 Adapter,乃至于封装一个能提高生产效率的 Adapter,是离不开对 ListView、GridView 到 RecyclerView 等一系列视图的 Item 复用机制的理解和掌握的。不熟悉的朋友们请至 http://blog.csdn.net/lmj623565791/article/details/24333277 学习
正文
我还依稀记得最早是这么写一个 Adapter 的(为什么是依稀)
BaseAdapter adapter = new BaseAdapter() { @Override public int getCount() { return list.size(); } @Override public String getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = inflater.inflate(layoutId, parent, false); TextView textView = convertView.findViewById(textViewId); Button button = convertView.findViewById(buttonId); String data = getItem(position); textView.setText(data); button.setOnClickListener(onClickListener); return convertView; } };
BaseAdapter adapter = new BaseAdapter() { @Override public int getCount() { return list.size(); } @Override public String getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = inflater.inflate(layoutId, parent, false); viewHolder = new ViewHolder(); viewHolder.textView = convertView.findViewById(textViewId); viewHolder.button = convertView.findViewById(buttonId); } else { viewHolder = (ViewHolder) convertView.getTag(); } String data = getItem(position); viewHolder.textView.setText(data); viewHolder.button.setOnClickListener(onButtonClickeListener); convertView.setTag(viewHolder); convertView.setOnClickListener(onConvertViewClickedListener); return convertView; } };
class ViewHolder { TextView textView; Button button; }
这样子写基本上没有遇到遇到太大问题,也就最初容易遇到因为 item 复用导致的各种混乱,在理解了复用机制之后其实很容易避免。我也曾经见到过将 convertView 传入 ViewHolder 中,在 viewHolder 里去实现大部分逻辑的写法,这里就不一一赘述了。
现在来想一下,写一个 Adapter,我们要做些什么?大致有这些吧:
1.实现 BaseAdapter 的 getCount、getItem、getItemId 这三个方法;
2.新建一个 ViewHolder 类,当中要包含一个 item 中需要操作的所有 view;
3.在 BaseAdapter 的 getView 方法中实现 item 复用,处理好 viewHolder 与 convertView 的关系;
4.处理 item,设置数据至 view ,添加监听等。
看上去也不太多嘛,就4步。但是实际上多写几次就很难受了,要是项目中 ListView、GridView 特别多,估计能把一只猿活活写吐了!
因为1、2、3的代码基本上每次都差不多,不同之处大多都在于4。一个复杂的 ListView 写下来感觉腰酸背痛手抽筋,简单的则感觉不会再爱了,毕竟花在写4的时间上好像远远小于123的重复工作。久而久之,我一听到要做 ListView 就会这样 -->
然后在一个月黑风高的夜晚,我意外得到了一件神器
public class ViewHolder { public static <T extends View> T get(View view, int id) { SparseArray<View> viewHolder = (SparseArray<View>) view.getTag(); if (viewHolder == null) { viewHolder = new SparseArray<View>(); view.setTag(viewHolder); } View childView = viewHolder.get(id); if (childView == null) { childView = view.findViewById(id); viewHolder.put(id, childView); } return (T) childView; }}
我们再看看这神器到底能干什么
BaseAdapter adapter = new BaseAdapter() { @Override public int getCount() { return list.size(); } @Override public String getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(layoutId, parent, false); } TextView textView = ViewHolder.get(convertView, textViewId); Button button = ViewHolder.get(convertView, buttonId); String data = getItem(position); textView.setText(data); button.setOnClickListener(onButtonClickListener); return convertView; } };
完全不用专门写 ViewHolder 类了有木有,对于我这样的懒人简直就是福音
以上就是神器 ViewHolder 的功效。
难道这是全部了吗?作为一个懒惰的程序猿,相信大家肯定和我一样不满足于此。放眼上述的代码,不管是哪个 adapter 都写了几个重复的方法,那些方法要怎么干掉呢?
其实,一个简单的基类加上对泛型的支持就可以了
public abstract class ListAdapter<T> extends BaseAdapter {protected abstract void setItem(View convertView, T data, int position);protected List<T> mData;protected Context mContext;protected LayoutInflater mInflater;protected int mLayoutRes;public ListAdapter(Context context, List<T> data, int layoutRes) {this.mData = data;this.mContext = context;this.mLayoutRes = layoutRes;this.mInflater = LayoutInflater.from(mContext);}/** * 刷新 adapter * 考虑到可能会发生数据完全改变的情况,故提供此方法 * @param data */public void refresh(List<T> data) {try {this.mData = data; notifyDataSetChanged();} catch (Exception e) {e.printStackTrace();}}@Overridepublic int getCount() {return mData.size();}@Overridepublic T getItem(int position) {return mData.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {try {if (convertView == null) {convertView = mInflater.inflate(mLayoutRes, null);}setItem(convertView, getItem(position), position);} catch (Exception e) {e.printStackTrace();}return convertView;}public <V extends View> V getChildView(View view, int id) {return ViewHolder.get(view, id);}}
封装到此结束,让我们看看是怎么使用的吧
BaseAdapter adapter = new ListAdapter<String>(MainActivity.this, list, layoutId) { @Override protected void setItem(View convertView, String data, int position) { TextView textView = getChildView(convertView, textViewId); textView.setText(data); getChildView(convertView, buttonId) .setOnClickListener(onButtonClickListener); } };
没仔细看前面代码的围观群众:WTF?这就完了?
没错,传入上下文、数据集合,还有布局文件,重写一个 setItem 方法就完了。相比最初的 adapter,我们只需要专注于布局、数据和视图的绑定,已经事件的监听,不需要重写相同的代码,不需要写累赘的 ViewHolder 类,不需要写八股文一般的 Item 复用代码。
虽然并不完美,也还没做到极简,但一个简单好用的 Adapter 已经初步成型了。谢谢各位看官赏脸看到现在。
下一篇文章打算在这次的 ListAdapter 的基础上封装 RecyclerView 的 Adapter,并且提供对 ItemType 的支持方式的参考思路。
项目源码:https://github.com/neverwoodsS/zy-open
- Android 一起来封装一个简单易用的Adapter
- android 简单的adapter封装
- Android Adapter的简单封装
- Android 一起来封装一个 RecyclerViewAdapter
- Adapter的简单封装
- android RecycleView Adapter简单封装
- Recyclerview Adapter 的简单封装
- RecyclerView.Adapter 的简单封装
- 简单封装RecyclerView的Adapter
- Android-对ListView的Adapter的一种简单封装
- Android-万能 Adapter 封装(实现textview,imageView 的简单封装,封装 jar 包)
- Android---封装ListView的Adapter
- Android 封装RecyclerView的Adapter
- 一个很好的RecyclerView的Adapter封装
- ListView中adapter的简单封装
- android Toobar的一个简单封装
- Android关于Log的一个简单封装
- Android 封装一个简单的SDK基本思路.
- eclipse jni (C/C++)代码提示
- Python & PyCharm & Django 搭建web开发环境
- 使用FFmpeg实现的转码器
- 在Centos7下源码安装配置Redis
- Android加载大图Bitmap发生OOM(Out Of Memmory Error)解决方案
- Android 一起来封装一个简单易用的Adapter
- JavaScript变量、作用域、内存、垃圾回收
- 播放音频文件
- Android源码编译(2)----建立编译环境
- 剑指offer——查找一个字符串中第一次出现一次的字符(哈希直接定址法)
- LIB和DLL的区别与使用
- T-SQL 学习笔记
- 领域模型和领域对象的概念
- 关于C#5.0异步编程与6.0新特性的总结