Android多类型抽象适配

我的CSDN博客


我的GitHub


我的GitHub博客

适配器的总结和使用


最新源代码下载

访问密码 9b16

更新:结合单类型抽象适配和分类适配的相关更新,对多类型抽象适配器进行了更新,以下代码是最新的。

上一篇文章介绍了如何进行分类适配,看过的小伙伴可以虽然比较完美的实现了分类适配以及复用,但是代码相当繁琐,我们有两种类型时已经出现了多层if嵌套,如果有三四种类型,估计自己都要转晕了,而且就像我们对单类型适配器抽象时做的,避免重复代码!如果没看过上一篇,建议浏览一下,这里写的很多都是基于第一篇的。

1.抽象ViewHolder

public static class MultiViewHolder extends ViewHolder{        /** * SparseArray */        private SparseArray<View> cacheViews;        private View itemView;        public MultiViewHolder(View itemView, int viewCount) {            super();            this.itemView = itemView;            cacheViews = new SparseArray<View>(viewCount);        }        @Override        public View getView(int resId) {            View v = cacheViews.get(resId);            if (v == null) {                v = itemView.findViewById(resId);                if (v != null) {                    cacheViews.put(resId, v);                }            }            return v;        }}

是不是发现跟第一篇的ViewHolder一模一样,本身ViewHolder就是维护UI的一个类,这里使用稀疏数组存储UI控件,又包含了获取控件的方法本身已经很完善了,后面我们会对ViewHolder进行进一步的完善附加功能。

2.获取类型的方法getType()

我们在分类适配的时候不可避免的要获得数据的对象,以此作为根据装载不同的布局文件,可能有人会说,在写bean类时加一个获取类型的方法就ok了,那么我们又如何保证在抽象的父类中可以直接调用这个方法呢,强制类实现一个方法!接口

/** 1. 接口,分类适配的对象需要实现的接口,目的是约束实体类实现getType方法 2. 3. @author chendong 4. */public interface MultiEasyAdapterInterface {    public int getType();}

没什么好说的,接口很简单

3.抽象分类适配器

适配器的抽象稍微复杂一点

3.1定义类

  1. 我们需要避免在子类中避免重复编码,同时在子类实现自己的方法,使用抽象父类。
  2. 我们不了解传递进来的数据是什么类型,使用泛型。
  3. 我们需要限制传进来的数据必须实现获得获得子类的方法,所以必须要求数据实现MultiEasyAdapterInterface接口,使用泛型限定符确定上限。
public abstract class MultiEasyAdapter<T extends MultiEasyAdapterInterface> extends BaseAdapter {}

3.2成员变量

根据传统的写法,LayoutInflater 和数据集自然是必不可少的

private LayoutInflater layoutInflater;private List<T> datas;

分析一下其他成员,根据上一篇传统分类适配的写法,我们姑且忽略类型的差异

  1. 每个类型需要一个布局资源文件id
  2. 每个类型布局文件中字UI控件的个数(用来优化)
  3. 每个类型一个唯一的键值(用来解决复用Item空指针的问题)
    ####我们用一个实体类存储这些信息
** * 存储类型信息的实体类 * * @author chendong * @功能:分类适配器配置信息实体类 */public class MultiEasyAdapterEntity {    /** * @param type * item类型,int类型变量,Item是什么类型的就填写什么类型 * @param resId * 资源id,对应类型的资源id,你需要装载的资源文件的ID * @param viewCount * 资源文件中对应的需要获取的视图的个数 */    public MultiEasyAdapterEntity(int type, int resId, int viewCount) {        super();        this.resId = resId;        this.viewCount = viewCount;    }    private int type;    private int resId;    private int viewCount;    public MultiEasyAdapterEntity() {        super();    }}

可能有点繁琐,type和viewCount 可以省略掉,加入type是为了更灵活的获得数据类型,viewCount则是为了优化SparseArray,综上第三个成员变量,就是使用type作为键,MultiEasyAdapterEntity作为值的一个SparseArray,他的作用就是存储不同类型的数据适配时需要的配置信息,有点类似配置文件的意思。

private SparseArray<MultiEasyAdapterEntity> Res4Type;

3.3完善代码

结合分类适配的方法,变量我们已经存储到了SparseArray中,所以代码就很清晰了

/** * version 2<br/> 注意事项:类型数为n时,那么定义的类型必须在0-n-1之间,这是使用listview自带缓存的要求。 * 抽象适配器升级版,可以进行分类适配,使用了模板方法模式,将设置item显示内容的部分抽象到了类外<br/> * @param <T> <br/>必须实现MultiEasyAdapterInterface接口{@link MultiEasyAdapterInterface}<br/> * @author chendong */public abstract class MultiEasyAdapter<T extends MultiEasyAdapterInterface>        extends BaseAdapter {    private LayoutInflater layoutInflater;    private List<T> datas;    private SparseArray<MultiEasyAdapterEntity> Res4Type;    private Context context;    /** * @param context 上下文对象 * @param datas 数据集 * @param Res4Type 资源配置文件{@link MultiEasyAdapterEntity}this is like a config entity */    public MultiEasyAdapter(Context context, List<T> datas,                            SparseArray<MultiEasyAdapterEntity> Res4Type) {        super();        this.layoutInflater = LayoutInflater.from(context);        this.datas = datas;        this.Res4Type = Res4Type;        this.context = context;    }    protected Context getContext(){        return context;    }    protected List<T> getDatas(){        return datas;    }    public void swapData(List<T> datas){        this.datas = datas;        notifyDataSetChanged();    }    @Override    public int getViewTypeCount() {        return Res4Type.size();    }    @Override    public int getItemViewType(int position) {        return datas.get(position).getType();    }    public int getCount() {        return datas.size();    }    public Object getItem(int position) {        return datas.get(position);    }    public long getItemId(int position) {        return position;    }    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder holder = null;        /* get the type*/        int type = datas.get(position).getType();        if (convertView == null) {            int resId = Res4Type.get(type).getResId();            convertView = layoutInflater.inflate(resId, parent, false);            holder = new ViewHolder(convertView, Res4Type.get(type)                    .getViewCount());            convertView.setTag(holder);            bindListener4View(holder,datas.get(position), type, position);        } else {            holder = (ViewHolder) convertView.getTag();        }        bindData4View(holder,datas.get(position), type, position);        return convertView;    }    /** * 绑定数据 * bind data * * @param holder the viewholder * @param type data's type * @param data data */    public abstract void bindData4View(ViewHolder holder, T data, int type,int pos);    /** * 绑定监听 * bind listener * * @param holder the viewholder * @param type data's type * @param pos position */    public abstract void bindListener4View(ViewHolder holder, T data, int type,int pos);}

测试

listview = (ListView) findViewById(R.id.listview);        list = new ArrayList<Student>();        for (int i = 0; i < 20; i++) {            if (i % 5 == 0)                list.add(new Student("name" + i, "age" + i, "sex", 3));            else                list.add(new Student("name" + i, "age" + i, "sex",                        i % 2 == 0 ? 1 : 2));        }        SparseArray<MultiEasyAdapterEntity> sparseArray = new SparseArray<MultiEasyAdapterEntity>(                3);        sparseArray.put(1, new MultiEasyAdapterEntity(1, R.layout.item_type1,                4));        sparseArray.put(2, new MultiEasyAdapterEntity(2, R.layout.item_type2,                4));        sparseArray.put(3, new MultiEasyAdapterEntity(3, R.layout.item_type3,                4));        listview.setAdapter(new MultiEasyAdapter<Student>(                getApplicationContext(), list, sparseArray) {            @Override            public void bindData4View(ViewHolder holder,                    Student data, int type) {                ((TextView) holder.getView(R.id.tv_name)).setText(data                        .getName());                ((TextView) holder.getView(R.id.tv_sex)).setText(data.getSex());                ((TextView) holder.getView(R.id.tv_age)).setText(data.getAge()                        + "");                if (type == 3)                    ((TextView) holder.getView(R.id.tv_type)).setText(data                            .getType()+"");            }@Override            public void bindListener4View(ViewHolder holder,                    Student data, int type) {            //绑定监听事件            }        });

ps:

1.Student类,四个属性,name,age,sex,type(1,2,3)实现了MultiEasyAdapterInterface接口,这是必须的
2.根据type类型,将配置信息放到稀疏数组中,设置到适配器里
3.在抽象方法中根据type设置不同的类型数据

5.效果

大家可以看到三中布局适配的没有问题,只有蓝色背景的布局显示了type,他是类型3的数据

6.总结

到此适配器进阶就基本结束了,使用单类型抽象适配器,分类抽象适配器可以很简单地进行数据适配操作,我是把它整理成了工具类来使用的,后面一片文章会进行一些总结和优化,并上传源代码,希望有不足的地方大家指正。

更多相关文章

  1. 【Android】蓝牙开发——经典蓝牙:配对与解除配对 & 实现配对或连
  2. Qt on Android(安卓)实现App普通全屏、沉浸模式、粘性沉浸模式
  3. Android(安卓)App调用SDK 登录第一次总是失败的解决方法
  4. [置顶] android 程序开发的插件化 模块化方法 之二
  5. [置顶] Android(安卓)轻松实现网络交互模板
  6. [置顶] Android(安卓)自定义ViewGroup实现整个Item布局竖直跑马
  7. Android(安卓)bugs——RecyclerView scrollToPosition不会触发sc
  8. Android坐标系统常用方法属性总结
  9. Android(安卓)ROM分析(1):刷机原理及方法

随机推荐

  1. 使用组件构建Android应用程序
  2. Ubuntu 无线热点 Set Up A Wireless Hots
  3. android scrollview中嵌套expandablelist
  4. android中和c++中生产者和消费者模式
  5. android发送json并解析返回json
  6. Android(安卓)Bitmap换背景颜色
  7. Frist Android
  8. android实现好看的自定义提示框
  9. Android异步线程OkHttp Post请求Json数据
  10. android加载效果,带百分比的