Android开发技巧——BaseAdapter的另一种优雅封装
来源:互联网 发布:办公软件应用基础教程 编辑:程序博客网 时间:2024/06/06 05:34
RecyclerView虽然因其灵活性、高效性等特点而备受好评,但也不是一定得用它把ListView给替代掉。在某些场景中,ListView还是相对更适合的。比如数据量不大,不频繁更新,并且需要简单地设置一下divider或header、footer的时候,相对于RecyclerView的繁琐,ListView在实现上则表现得更方便和简洁。
过去的封装
在使用ListView的过程中,为了复用ListView中的convertView以及优化getView()时的findViewById操作,我们通常会引入一个ViewHolder类,来持有itemView的子view。但是不便的是,我们需要为每一种显示不同数据的ListView都重写其BaseAdapter的getView(),于是就有了对其的一种封装:
创建一个通常的ViewHolder,里面用SparseArray<View>
来缓存,如下:
public class ViewHolder { private final View itemView; private SparseArray<View> mHolderViews; public ViewHolder(View view) { itemView = view; view.setTag(this); mHolderViews = new SparseArray<>(); } public void hold(int... resIds) { for (int id : resIds) { mHolderViews.put(id, itemView.findViewById(id)); } } public <V> V get(int id) { return (V) mHolderViews.get(id); }}
再通过重写BaseAdapter的getView方法,作如下封装:
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { holder = createHolder(position, parent); convertView = holder.itemView; } else { holder = (ViewHolder) convertView.getTag(); } bindData(position, holder, getItem(position)); return convertView;}public abstract ViewHolder createHolder(int position, ViewGroup parent);public abstract void bindData(int position, ViewHolder holder, T data);
这样使用的时候只需要继承并实现两个抽象方法即可。
这样写法,在后来我觉得还是有些别扭的地方。一是使用的时候还是需要去继承我们封装过的Adapter;二是在bindData()
方法中,需要对每一个我们要设置的控件调用holder.get(id)
方法,才能开始赋值或进行其他的设置,当我们的item的控件较多时,这些调用会使bindData()
显得臃肿而不够纯粹,于是我又对其进行了另一种封装。
另一种优雅封装
这里我主要是通过接口解决重写Adapter的问题,然后再借鉴RecyclerView.ViewHolder,封装结果如下:
假设我们重写BaseAdapter的类为BaseListAdapter,那么首先定义它的一个静态内部类:
public static abstract class ViewHolder { public final View itemView; public ViewHolder(View itemView) { this.itemView = itemView; itemView.setTag(this); } }
然后我们定义一个接口,用于创建ViewHolder以及绑定数据,如下:
package com.githang.android.snippet.demo.adapter.adapter;import android.view.ViewGroup;public interface ViewCreator<T, H extends BaseListAdapter.ViewHolder> { H createHolder(int position, ViewGroup parent); /** * 设置列表里的视图内容 * * @param position 在列表中的位置 * @param holder 该位置对应的视图 */ void bindData(int position, H holder, T data);}
这里定义了两个泛型 ,一个是T,表示我们Adapter里的数据对象,另一个是H,为我们的ViewHolder的子类,表示我们最终创建出来的ViewHolder。
接下来,修改我们的BaseListAdapter
,如下:
public class BaseListAdapter<T, H extends BaseListAdapter.ViewHolder> extends BaseAdapter { private final List<T> mData; private final ViewCreator<T, H> mViewCreator; public BaseListAdapter(ViewCreator<T, H > creator) { this(new ArrayList<T>(), creator); } public BaseListAdapter(List<T> data, ViewCreator<T, H> creator) { mData = data == null ? new ArrayList<T>() : data; mViewCreator = creator; } @Override public int getCount() { return mData.size(); } @Override public T getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final H holder; if (convertView == null) { holder = mViewCreator.createHolder(position, parent); convertView = holder.itemView; } else { holder = (H) convertView.getTag(); } mViewCreator.bindData(position, holder, getItem(position)); return convertView; } public void update(List<T> data) { mData.clear(); addData(data); } public void addData(List<T> data) { if (data != null) { mData.addAll(data); } notifyDataSetChanged(); } public static abstract class ViewHolder { public final View itemView; public ViewHolder(View itemView) { this.itemView = itemView; itemView.setTag(this); } }}
在这个BaseListAdapter
里,同样定义了两个泛型,与我们的ViewCreator
相同。我们创建ViewHolder及绑定数据的操作,通过调用该接口来执行(见getView方法),而该接口实例则通过构造方法传入。
这样,我们在使用的时候就可以先像使用RecyclerView一样,定义一个实现我们ViewHolder的子类,然后使我们的Fragment或Activity实现这个ViewCreator接口就可以了。
最后,我们还可以继承ViewHolder,封装一个通用的ViewHolder,代码如下:
public static class DefaultViewHolder extends ViewHolder { private SparseArray<View> mHolderViews; public DefaultViewHolder(View view) { super(view); mHolderViews = new SparseArray<>(); } public void hold(int... resIds) { for (int id : resIds) { mHolderViews.put(id, itemView.findViewById(id)); } } public <V> V get(int id) { return (V) mHolderViews.get(id); } }
接下来是使用示例:
public class SampleFragment extends Fragment implements ViewCreator<User,SampleFragment.UserViewHolder> { private BaseListAdapter<User, UserViewHolder> mAdapter = new BaseListAdapter<User, UserViewHolder>(this); @Override public UserViewHolder createHolder(int position, ViewGroup parent) { return new UserViewHolder(LayoutInflater.from(getActivity()).inflate(R.layout.item_user, parent, false)); } @Override public void bindData(int position, UserViewHolder holder, User user) { holder.name.setText(user.name); holder.email.setText(user.email); } static class UserViewHolder extends BaseListAdapter.ViewHolder { public final TextView name; public final TextView email; public UserViewHolder(View itemView) { super(itemView); name = (TextView) itemView.findViewById(R.id.name); email = (TextView) itemView.findViewById(R.id.email); } }}
全部的封装代码加上注释等也不过一百来行,但是可以看到,在这样的封装下,我们的代码已经变得很清晰。
本文的代码见:http://download.csdn.net/detail/maosidiaoxian/9700700
更详细的封装及相关代码见我的开源项目:https://github.com/msdx/AndroidSnippet/tree/master/library/src/main/java/com/githang/android/snippet/adapter
- Android开发技巧——BaseAdapter的另一种优雅封装
- Android开发——BaseAdapter的使用
- Android开发——BaseAdapter的优化
- Android之BaseAdapter的优雅实现
- Android开发技巧——PagerAdapter实现类的封装
- Android开发技巧——PagerAdapter实现类的封装
- Android开发技巧——PagerAdapter的再次简单封装
- Android开发技巧——PagerAdapter实现类的封装
- Android开发技巧——PagerAdapter实现类的封装
- Android开发技巧——PagerAdapter的再次简单封装
- Android开发技巧——PagerAdapter实现类的封装
- [android开发]封装BaseAdapter, 简便代码
- Android:BaseListAdapter——提高开发效率的BaseAdapter
- BaseAdapter的封装来实现模块化开发
- Android BaseAdapter的极简封装
- ruby 版,JavaBean的另一种优雅写法——Builder的代码生成器
- BaseAdapter的简单封装
- BaseAdapter的简单封装
- 英文符号大全
- stm32 中bootloader、startup_stm32f10x_md.s的作用
- nginx配置详解
- 3.4.6 Query DSL changes
- 欢迎使用CSDN-markdown编辑器
- Android开发技巧——BaseAdapter的另一种优雅封装
- joomla 3.6 component开发教程之二 component外部网站(site)
- 回归分析的可视化-nomogram
- 达内 JAVA UI设计 网络营销 嵌入式 正版高清全套视频
- 日常学习总结的知识点(1)
- 如何让Html页面的导航固定在浏览器顶部
- c语言==野指针形成原理、造成的危害及避免方法(22)
- 如何在tomcat下部署多个项目
- 动态加载javascript,引用外链