文章标题

         **小飞飞博客之  打造万能适配器**

在Android中ListView不得不说是一个使用频率好高的组件,那么为了提高开发效率我们就有必要将它封装起来;以便以后在编写ListView的适配器的时候随手几行代码将其潇洒的搞定。

那么现在我们要做的任务就是将我们正常书写的Adapter 给封装起来
下面是一个 中规中矩的 MyAdapter 继承 BaseAdapter的代码

public class MyAdapter extends BaseAdapter {
//Context 对象的传入 为的初始化加载布局的LayoutInflater
    private Context context;
 //lisetview 所绑定的数据集
  private List<DataBean> beanList;
   private LayoutInflater layoutInflater;

    public MyAdapter(Context context, List<DataBean> beanList) {
        this.context = context;
        this.beanList = beanList;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override

    public int getCount() {
        return beanList.size();
    }

    @Override
    public Object getItem(int position) {
        return beanList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
/*R.layout.list_myitem 为item条目的布局,还有一些组件的 初始化操作我们都去给用户提供 从外部传入的入口,以及convertView 的复用优化技术我也不再多提,相信大家都知道*/

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHold viewHold = null;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.list_myitem, parent, false);
            viewHold = new ViewHold();
            viewHold.dec_tv = (TextView) convertView.findViewById(R.id.dec_tv);
            viewHold.time_tv = (TextView) convertView.findViewById(R.id.time_tv);
            viewHold.phone_tv = (TextView) convertView.findViewById(R.id.phone_tv);
            viewHold.title_tv = (TextView) convertView.findViewById(R.id.title_tv);
            convertView.setTag(viewHold);

        } else {
            viewHold = (ViewHold) convertView.getTag();
        }
        viewHold.dec_tv.setText(beanList.get(position).getDesc());
        viewHold.title_tv.setText(beanList.get(position).getTitle());
        viewHold.phone_tv.setText(beanList.get(position).getPhone());
        viewHold.time_tv.setText(beanList.get(position).getTime());

        return convertView;
    }
//这里使用了ViewHold 说白了就是一个持有类 为的是 初始化组件(findviewbyid操作)不去执行那么多遍
    static class ViewHold {
        TextView title_tv;
        TextView dec_tv;
        TextView phone_tv;
        TextView time_tv;
    }
}

对于上面代码 大家估计是码的都快吐了,那么接下来我们将它抽取成为一万能的适配器  我们分析发现BaseAdapter 里面大多数代码都是重复的 包括复写的几个方法都是固定的几个,唯一特殊的方法就是getView方法了。但是getView 方法的流程也是定死了的,大概分为一下几部
   1: 为了复用convertView 布局, 先判空  为空去加载布局
   2new 出viewhold 去初始化viewhold里持有的组件,然后将viewhold 通过View类里的  setTag() 方法将viewhold对象寄存在  convertView对象中
   3:如果convertView 不为空的话直接 用 getTag() 方法将持有组件的viewhold  对象取出
   4:接下来设置 组件上对应数据的值  
   5:最后返回 convertView  就可以了

我们可以发现上面的几步,也仅仅是第 4 步,每个人的操作不一样,因为每个人的数据不同;

接下来  我们写一个ViewHold类 将以上共同的  1 2 3 5 步给封装起来

public class ViewHold {
private int postion;
private View mConvertView;
private Context mContext;
//这个集合 用于给用户初始化 控件。也就是说 对应的View控件 和Id 键值成对
//存放在集合里 这样就不必 每一次都去 findViewById 了
private SparseArray mSparseArray = new SparseArray<>();

public View getmConvertView() {
    return mConvertView;
}

public ViewHold(int postion, View mConvertView, Context mContext, int ResLayoutId, ViewGroup parent) {
    mConvertView = LayoutInflater.from(mContext).inflate(ResLayoutId, parent, false);
    this.postion = postion;
    this.mConvertView = mConvertView;
    this.mContext = mContext;
    mConvertView.setTag(this);
}

//相当于将 判空操作 和 setTag 与 getTag 操作执行了
public static ViewHold getViewHold(Context mContext, int postion, View mConvertView, int ResLayoutId, ViewGroup parent) {

    if (mConvertView == null) {
        //跳转到 构造函数  为空加载布局 携带 viewHold 操作
        return new ViewHold(postion, mConvertView, mContext, ResLayoutId, parent);
    } else {
        //不为空 取出 ViewHold 对象
        ViewHold viewhold = (ViewHold) mConvertView.getTag();
        return viewhold;
    }

}

//这个方法 为了解决用户书写 适配器 初始化控件的控件的操作;
//具体逻辑 如果集合中没有还有存放初始化好的组件 就FindViewById 加入集合,下次用有就直接取就OK了
//使用 泛型 T 的目的是 我并不知道 你有哪些控件 我只能知道的是的组件必然是View的子类,你拿到View自行强转
public T getView(int ResId) {

    View view = mSparseArray.get(ResId);

    if (view == null) {
        view = mConvertView.findViewById(ResId);
        mSparseArray.put(ResId, view);
    }
    return (T) view;
}

}




这样一来在写BaseAdapter的getView()方法时
 我们只需要 :

public View getView(int position, View convertView, ViewGroup parent) {
ViewHold viewHold = ViewHold.getViewHold(mContext, position, convertView, R.layout.mylist_item, parent);
((TextView) viewHold.getView(R.id.id_title)).setText(list_data.get(position).getmTitle());
((TextView) viewHold.getView(R.id.id_content)).setText(list_data.get(position).getmContent());
((TextView) viewHold.getView(R.id.id_time)).setText(list_data.get(position).getmTime());

    return viewHold.getmConvertView();
}

相比以前是不是简单多了
先 getVIewHold()  再找组件  再返回 convertView
中间的初始化组件的是必须要写的,但 开始的getVIewHold() 和 最后的 返回convertView 操作我们还可以继续抹掉

写一个名为CompanyAdapter的抽象类 继承 BaseAdapter

public abstract class CompanyAdapter extends BaseAdapter {
protected Context mContext;
protected List list_data;
protected int LayoutItmeResId;

public CompanyAdapter(Context mContext, List<T> list_data, int LayoutItemResId) {
    this.list_data = list_data;
    this.mContext = mContext;
    this.LayoutItmeResId = LayoutItemResId;
}

@Override
public int getCount() {
    return list_data.size();
}

@Override
public Object getItem(int position) {

    return list_data.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHold viewHold = ViewHold.getViewHold(mContext, position, convertView, LayoutItmeResId, parent);
    initView(viewHold, position);
    return viewHold.getmConvertView();
}

protected abstract void initView(ViewHold viewhold, int position);

}



可以看到我们将要做的相同的操作全部放在了这个抽象类中
只提供了一个抽象方法  initView方法  那便你为组件设置值的接口
那么我们的万能 适配器基本上算大功告成了

让我们来使用一下看看![里面MyAdapter包里是我们刚刚写好的两个工具类](https://img-blog.csdn.net/20160521115909318)
里面MyAdapterUtils包里是我们刚刚写好的两个工具类

public class MainActivity extends AppCompatActivity {
private List dataRusList;
private ListView mListView;
private MyAdapter myAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    dataRusList = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        DataRus mDataRus = new DataRus("万能适配器" + i, "我的第" + i + "个条目", "2016.5." + (20+i));
        dataRusList.add(mDataRus);
    }

    mListView = (ListView) findViewById(R.id.listview);
    //使用的时候传3个参数 最后一个为item的布局
    myAdapter = new MyAdapter(this, dataRusList,R.layout.mylist_item);
    mListView.setAdapter(myAdapter);
}

}

Item的布局就不贴了 重点是适配器
public class MyAdapter extends CompanyAdapter<DataRus> {
    public MyAdapter(Context mContext, List<DataRus> list_data, int LayoutItemResId) {
        super(mContext, list_data, LayoutItemResId);
    }
//这里初始化你的控件
    protected void initView(ViewHold viewHold,int position) {
        ((TextView)viewHold.getView(R.id.id_title)).setText(list_data.get(position).getmTitle());
        ((TextView) viewHold.getView(R.id.id_content)).setText(list_data.get(position).getmContent());
        ((TextView) viewHold.getView(R.id.id_time)).setText(list_data.get(position).getmTime());
    }
}

最后附上我最后 丑丑的运行结果图,没怎么认真的找素材,全是TextView

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值