Android自学笔记(一):Adapter设计思想浅析

**原创不易,感谢阅读!笔者能力有限,欢迎在评论区交流指正,不胜感激٩(๑>◡<๑)۶ **

为什么要自定义一个BaseAdapter

Adapter的设计思路,就像是C++中的迭代器,我们都知道在C++当中,迭代器是容器和算法之间进行遍历和处理操作的桥梁。对于Android的交互模式来说,Adapter就是这个桥梁作用了。

所以自定义BaseAdapter,就相当于我们需要自己设计一个迭代器,根本原因,我认为是为了适配自定义的前端设计、自定义事件逻辑,以及适配自定义的结构体所需。

自定义BaseAdapter的使用场景

自定义的BaseAdapter用来作什么呢?用来满足这样的交互场景:
获得数据以用来进行适配(相当于取容器数据。对于很熟悉Android开发的

  1. 程序员大神们,你们一定很熟悉了,例如一些存放字符串、图片之类的数组,或者是直接从SQLite去获取,这个我还不太熟悉)
  2. 获得数据之后用来适配什么呢?是用来适配前端的UI布局(例如一个ListView,我们一般需要为其设计整体的layout布局,然后我们需要对ListView中的每一个Item也设计其布局。)

如何设计一个自定义的BaseAdapter

设计BaseAdapter接受怎样的数据类型

也就是说:为BaseAdapter这个类添加相应的成员变量。

BaseAdapter的数据迭代策略

需要重载一些重要的方法:

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html

	/**
	/* 获取Adapter所拿到的容器的大小 
	**/
    @Override
    public int getCount() {
        return mData.size();
    }
    
	/**
	/* 取Adapter当前迭代位置的数据元素
	**/
    @Override
    public Object getItem(int position) {
        return null;
    }

	/**
	/* 获取当前迭代所处的位置
	**/
    @Override
    public long getItemId(int position) {
        return position;
    }

这里的position我觉得很有意思,可以理解为这个适配器内部使用的迭代指针(比如Adapter::Iterator?本人对C++编程风格比较心水哈哈哈:-D)。

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
img_icon.setBackgroundResource(mData.get(position).getaIcon());
txt_aName.setText(mData.get(position).getaName());
txt_aSpeak.setText(mData.get(position).getaSpeak());

为BaseAdapter的元素(Item)数据适配对应的布局(Item-layout)

ListView 中的每一个 Item都有其固定的布局。

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list_animal,parent,false);

在ListView-Item-layout下,指定各个数据元素应当和该布局中的哪些元素相对应:

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
ImageView img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
TextView txt_aName = (TextView) convertView.findViewById(R.id.txt_aName);
TextView txt_aSpeak = (TextView) convertView.findViewById(R.id.txt_aSpeak);

这些R.id都是在Item-layout中设定的。

此外,其中可能涉及到读取Resource的图片资源,不是字符串或者数字这样的简单数据。例如icon image。

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
img_icon.setBackgroundResource(mData.get(position).getaIcon());

至于数据是自己写死的,还是通过SQLite获取的,还是其他方式,和这里没有关系。对于Adapter而言只要拿到对应的容器数据就好了。

在Activity中使用自定义的BaseAdapter

首先实例化一个BaseAdapter对象。以下的代码中,完成了两件事情:

  1. 实例化了一个BaseAdapter对象。

    (这样说不太严谨,应该说AnimalAdapter是我们基于BaseAdapter这个类自定义了一个AnimalAdapter类,然后用AnimalAdapter类实例化了一个AnimalAdapter对象。但是本文讨论的是BaseAdapter,所以我觉得说实例化BaseAdapter对象这种表述更加符合本文的初衷)

  2. 利用构造函数,同时完成了BaseAdapter对象的数据适配。

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
mAdapter = new AnimalAdapter((LinkedList<Animal>) mData, mContext);

然后我们为我们已经好的ListView布局添加上这个BaseAdapter,让我们的适配器与布局相关联。

首先将ListView对象和ListView-layout关连起来:

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
list_animal = (ListView) findViewById(R.id.list_animal);

然后为ListView对象指定BaseAdapter:

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-listview.html
list_animal.setAdapter(mAdapter);

然后……然后应该就完成了叭?✧(≖ ◡ ≖✿

其实并不是。因为这里的Adapter只有数据呈现,我们只是把拿到的容器数据读出来,然后在前端做了一个数据呈现而已。顶多是ListView可以如同滚动条一样的滑来滑去。

其实,我们经常会要在ListView中勾选一些按钮,或者是RadioButton之类的,总之交互的形式可以有很多种,这意味着Adapter也需要对相应的点击事件有所处理。举个形象一些的例子,例如手机短信,我希望点击某条短信之后,该短信能够显示“已读”,然后左下角的蓝色气泡会消除掉,然后标题字体的颜色会变成灰色,之类的效果。

为ListView中的Item添加点击事件逻辑

这一块我还在学习当中,后续会完善。(未完待续)

优化BaseAdapter的代码

这一节里让我们优化一下BaseAdapter的代码。优化点包括两个部分,convertView和ViewHolder,它们的作用是使得不用每一次都加载layout布局,减少重复的运行量。

此处优化是通过单例模式实现的,使用了静态类。代码如下:

// 参考链接:https://www.runoob.com/w3cnote/android-tutorial-baseadapter.html
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    if(convertView == null){
        // 为convertView加载Item-layout布局
        convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list_animal,parent,false);
        holder = new ViewHolder();
        // 为视图持有者关联convertView中所保存的对应布局元素id
        holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
        holder.txt_aName = (TextView) convertView.findViewById(R.id.txt_aName);
        holder.txt_aSpeak = (TextView) convertView.findViewById(R.id.txt_aSpeak);
        // 将视图持有者存储到convertView中
        convertView.setTag(holder);
    }else{
        // convertView已经设置过了,那么此时就复用convertView中的视图持有者
        holder = (ViewHolder) convertView.getTag();
    }
    // 这里和之前没有优化过的BaseAdapter代码是统一的
    holder.img_icon.setBackgroundResource(mData.get(position).getaIcon());
    holder.txt_aName.setText(mData.get(position).getaName());
    holder.txt_aSpeak.setText(mData.get(position).getaSpeak());
    return convertView;
}

// 在这个例子中,视图持有者持有三种成员数据,这和我们输入的容器元素数据(结构体)是统一的。
static class ViewHolder{
    ImageView img_icon;
    TextView txt_aName;
    TextView txt_aSpeak;
}

虽然这样子的写法相比没有优化过的版本而言,要拗口不少,但是这其实是更加通用的形式,也是大部分人使用的开发模板。通过一点点慢慢梳理,我们还是能由此理明白这个代码为什么要写成这个样子了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值