Android之自定義實(shí)現(xiàn)BaseAdapter(通用適配器一)
通過(guò)前面的優(yōu)化布局之后,我們接著來(lái)講如何打造一個(gè)通用的適配器,那么通用適配器能干嗎呢?很簡(jiǎn)單,減少我們對(duì)代碼的書(shū)寫(xiě),下面開(kāi)始上代碼了。
MyAdapter.java
public class MyAdapter extends BaseAdapter {
private List<Student> data;
public MyAdapter(List<Student> data) {
this.data = data;
}
@Override
public int getCount() {
return data == null ? 0 : data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/**
*
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView == null){
//解析布局
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
//創(chuàng)建ViewHolder持有類(lèi)
holder = new ViewHolder();
//將每個(gè)控件的對(duì)象保存到持有類(lèi)中
holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
//將每個(gè)convertView對(duì)象中設(shè)置這個(gè)持有類(lèi)對(duì)象
convertView.setTag(holder);
}
//每次需要使用的時(shí)候都會(huì)拿到這個(gè)持有類(lèi)
holder = (ViewHolder)convertView.getTag();
//然后可以直接使用這個(gè)類(lèi)中的控件,對(duì)控件進(jìn)行操作,而不用重復(fù)去findViewById了
holder.tvName.setText(data.get(position).getName());
holder.tvSex.setText(data.get(position).getSex());
return convertView;
}
/**
* 通過(guò)這個(gè)類(lèi)來(lái)保存當(dāng)前所有的控件id
*/
static class ViewHolder{
TextView tvName;
TextView tvSex;
}
}
在上面的代碼中,我們先看看有哪些代碼的格式或形式都是重復(fù)在使用的,首先不難看出,public int getCount() 、public long getItemId(int position) 、public long getItemId(int position)這三個(gè)方法是不是每次都要實(shí)現(xiàn)呢,由此我們可以先將這些代碼提取出來(lái),放到MyBaseAdapter中,由于我們每次的重要部分是實(shí)現(xiàn)getView方法,所以這個(gè)方法我們不需要在這里面寫(xiě),直接將MyBaseAdapter設(shè)置為抽象類(lèi)就可以了,然需要實(shí)現(xiàn)getView的類(lèi)來(lái)繼承他即可,因此MyAdapter可以繼承MyBaseAdapter然后實(shí)現(xiàn)getView方法即可
MyBaseAdapter.java
public abstract class MyBaseAdapter extends BaseAdapter {
protected List<Student> data;
public MyBaseAdapter(List<Student> data){
this.data = data;
}
@Override
public int getCount() {
return data == null ? 0 : data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
}
MyAdapter.java
public class MyAdapter extends MyBaseAdapter {
public MyAdapter(List<Student> data) {
super(data);
this.data = data;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView == null){
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
holder = new ViewHolder();
holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
convertView.setTag(holder);
}
holder = (ViewHolder)convertView.getTag();
holder.tvName.setText(data.get(position).getName());
holder.tvSex.setText(data.get(position).getSex());
return convertView;
}
static class ViewHolder{
TextView tvName;
TextView tvSex;
}
}
這樣,每次自定義只需要繼承MyBaseAdapter就可以了,不過(guò)還是那句話(huà),沒(méi)有最優(yōu),只有更優(yōu),所以我們還要接著優(yōu)化,接著封裝,那么我們接著從上面的getView方法中看,還有哪些代碼是我們經(jīng)常重復(fù)使用到的代碼呢?其實(shí)你會(huì)發(fā)現(xiàn)每次我們都需要操作相同的這段代碼:
ViewHolder holder = null;
if(convertView == null){
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
holder = new ViewHolder();
holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
convertView.setTag(holder);
}
holder = (ViewHolder)convertView.getTag();
holder.tvName.setText(data.get(position).getName());
holder.tvSex.setText(data.get(position).getSex());
return convertView;
}
我們可以先再次理解下這段代碼,首先我們每次都要?jiǎng)?chuàng)建一個(gè)holder持有者對(duì)象,設(shè)置到對(duì)應(yīng)的converView的setTag中,然后,每次要拿到hoder對(duì)象,對(duì)hoder對(duì)象中的控件進(jìn)行操作,對(duì)于上面的代碼我們可以直接將他簡(jiǎn)化為以下幾個(gè)步奏
1.ViewHolder holder = 拿到holder //每次拿到對(duì)應(yīng)的holder對(duì)象即可
2.TextView tv = holder.getView() //拿到每個(gè)控件對(duì)應(yīng)的id
3. tv.setText() //對(duì)控件進(jìn)行操作
4. return view //返回view即可
下面開(kāi)始寫(xiě)一個(gè)通用的ViewHolder通用類(lèi),來(lái)優(yōu)化我們的實(shí)現(xiàn),代碼如下:
ViewHolder.java
public class ViewHolder {
//被點(diǎn)擊的當(dāng)前位置
private int position;
//用一個(gè)map集合來(lái)保存每個(gè)控件的id,這個(gè)SparseArray是android提供的一個(gè)比map使用效率更高的一個(gè)
//集合,但是局限是,key只能是int類(lèi)型,所以當(dāng)鍵值對(duì)涉及到key是int類(lèi)型時(shí),可以?xún)?yōu)先考慮使用這個(gè)集合
private SparseArray<View> array;
//復(fù)用的布局
private View convertView;
//上下文
private Context context;
//解析的布局資源id
private int layout;
public ViewHolder(){
}
//帶三個(gè)構(gòu)造的方法,這里將構(gòu)造方法私有,防止外界去創(chuàng)建,通過(guò)自身的靜態(tài)方法去創(chuàng)建對(duì)象即可
private ViewHolder(ViewGroup parent,int position,int layout){
this.position = position;
this.context = parent.getContext();
//每次創(chuàng)建對(duì)象,就將布局解析出來(lái)
convertView = LayoutInflater.from(parent.getContext()).inflate(layout,null);
//然后將對(duì)象保存到convertView對(duì)應(yīng)的setTag中,方便每次該獲取
convertView.setTag(this);
array = new SparseArray<>();
}
//通過(guò)這個(gè)方法,可以創(chuàng)建ViewHolder對(duì)象
public static ViewHolder getHolder(View convertView, ViewGroup parent, int position,int layout){
//每次判斷converView是否為空,如果為空就直接返回這個(gè)創(chuàng)建的對(duì)象
if(convertView == null){
return new ViewHolder(parent,position,layout);
}else{
//不為空的情況,就跟我們上面的代碼一樣,每次通過(guò)復(fù)用的控件拿到對(duì)應(yīng)的ViewHolder對(duì)象
ViewHolder holder = (ViewHolder)convertView.getTag();
//這里一定要更新下下標(biāo)的位置,雖然對(duì)象相同,但是我們每次都要更新現(xiàn)有的位置,
holder.position = position;
//返回已經(jīng)創(chuàng)建好的holder對(duì)象
return holder;
}
}
/**
* 這個(gè)方法是通過(guò)控件id拿到對(duì)應(yīng)的控件
*/
public <T extends View> T getView(int viewId){
//每次通過(guò)viewId鍵去拿到到對(duì)應(yīng)的控件
View view = array.get(viewId);
//如果為空,表示該集合中還沒(méi)有存入該控件
if(view == null){
//先要去通過(guò)converView拿到控件id
view = convertView.findViewById(viewId);
//保存到集合中,以便下次直接獲取
array.put(viewId,view);
}
//返回View的子類(lèi)控件,采用泛型的方便是不需要強(qiáng)制轉(zhuǎn)換了
return (T)view;
}
//得到converView布局
public View getConvertView(){
return convertView;
}
通過(guò)上面的代碼我們就已經(jīng)封裝好了一個(gè)通用的ViewHolder類(lèi)了,下面我們的MyAdapter.java則可以更加簡(jiǎn)單的只寫(xiě)一下代碼了:
public class MyAdapter extends MyBaseAdapter {
public MyAdapter(List<Student> data) {
super(data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = ViewHolder.getHolder(convertView,parent,position, R.layout.list_item);
TextView tvName = holder.getView(R.id.mTv1);
TextView tvSex = holder.getView(R.id.mTv2);
tvName.setText(data.get(position).getName());
tvSex.setText(data.get(position).getSex());
return holder.getConvertView();
}
}
好了,上面的代碼是不更簡(jiǎn)單了呢,其實(shí)我們這里只是封裝了ViewHolder類(lèi)哦,還有更通用的等著我們?nèi)シ庋b呢,下次我們需要封裝的就是如何把getView中的代碼再一次進(jìn)行封裝,已達(dá)到更優(yōu)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android TextView設(shè)置不同的顏色字體
這篇文章主要為大家詳細(xì)介紹了Android TextView設(shè)置不同的顏色字體,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Android仿微信圖片選擇器ImageSelector使用詳解
這篇文章主要為大家詳細(xì)介紹了Android仿微信圖片選擇器ImageSelector的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android 自定義gradle property詳解及實(shí)例代碼
這篇文章主要介紹了Android 自定義gradle property詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android開(kāi)發(fā)筆記之:AsyncTask的應(yīng)用詳解
本篇文章是對(duì)Android中AsyncTask的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
怎樣實(shí)現(xiàn)android http-post方法實(shí)例說(shuō)明
android http-post方法在開(kāi)發(fā)中如何實(shí)現(xiàn),具體代碼如下,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助2013-06-06
Android App中自定義View視圖的實(shí)例教程
這篇文章主要介紹了Android App中自定義View視圖的實(shí)例教程,詳細(xì)講解了如何在創(chuàng)建View中定義各種鎖需要的樣式屬性,需要的朋友可以參考下2016-04-04
Android使用Item Swipemenulistview實(shí)現(xiàn)仿QQ側(cè)滑刪除功能
大家都用過(guò)QQ,肯定有人好奇QQ滑動(dòng)刪除Item的效果是怎樣實(shí)現(xiàn)的,其實(shí)我們使用Swipemenulistview就可以簡(jiǎn)單的實(shí)現(xiàn)。這篇文章主要介紹了Android使用ItemSwipemenulistview實(shí)現(xiàn)仿QQ側(cè)滑刪除功能,需要的朋友可以參考下2017-02-02
Android使用fragment實(shí)現(xiàn)左側(cè)導(dǎo)航
這篇文章主要為大家詳細(xì)介紹了Android使用fragment實(shí)現(xiàn)左側(cè)導(dǎo)航,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02

