第一次寫(xiě)博客定躏,同時(shí)也是Android初學(xué)者澜掩,想在博客中記錄自己所學(xué)的一點(diǎn)知識(shí)购披,也算是總結(jié)吧。如果有什么不對(duì)的地方還請(qǐng)指證肩榕,好了下面直接進(jìn)入主題刚陡。
未封裝前
首先我們來(lái)看下沒(méi)有封裝前的,相信大家都很熟悉了株汉,但為了后面的封裝我寫(xiě)了一個(gè)簡(jiǎn)單的Adapter筐乳。代碼中的UIUtils為我寫(xiě)的工具類(lèi),就是對(duì)View.inflate的封裝乔妈,大家當(dāng)做View.inflate就好蝙云。(- -!)
private String[] data = new String[] { "hello", "world" };
public class Adapter extends BaseAdapter {
@Override
public int getCount() {
return data.length;
}
@Override
public String getItem(int position) {
return data[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
//1, 加載布局文件
convertView = UIUtils.inflate(R.layout.list_item);
holder = new ViewHolder();
//2, 初始化控件 findViewById
holder.tv = (TextView) convertView.findViewById(R.id.tv);
//3, 打tag
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
String content = getItem(position);
holder.tv.setText(content);
return convertView;
}
static class ViewHolder {
TextView tv;
}
}
看完之后大家可能覺(jué)得沒(méi)什么,寫(xiě)起來(lái)也很簡(jiǎn)單路召,那為什么要封裝呢勃刨?是的,如果你的項(xiàng)目中是使用一個(gè)listview那么寫(xiě)起來(lái)是不用封裝股淡,但如果你的項(xiàng)目中使用大量的ListView身隐,那你就要為每個(gè)ListView寫(xiě)個(gè)Adapter。從上述的代碼中我們可以看出有很多事重復(fù)的工作唯灵。那么這時(shí)候我們進(jìn)行封裝可以使我們的代碼量減少很多贾铝。
第一步封裝
首先我們觀察adapter中有三個(gè)方法是固定寫(xiě)法
- getCount()
- getItem(int position)
- getItemId(int position)
上述的三個(gè)方法基本都是固定寫(xiě)法沒(méi)上面變動(dòng),唯一變動(dòng)的就是數(shù)據(jù)的類(lèi)型,那么我們可以寫(xiě)一個(gè)ArrayList<T>并傳入一個(gè)泛型垢揩,這樣數(shù)據(jù)類(lèi)型的問(wèn)題就解決了大脉。然后就可以進(jìn)行封裝。在構(gòu)造方法中得到這個(gè)data然后根據(jù)data來(lái)適配水孩。
public abstract class MyBaseAdapter<T> extends BaseAdapter {
private ArrayList<T> data;
public MyBaseAdapter(ArrayList<T> data) {
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public T getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
... //代碼和上面的getView一樣
}
... //ViewHolder
}
這樣就封裝了三個(gè)方法,如下寫(xiě)個(gè)adapter繼承琐驴,這樣就只需簡(jiǎn)傳入一個(gè)自定義data就行了(當(dāng)然這里我只是簡(jiǎn)單的寫(xiě)個(gè)String俘种,你可以根據(jù)需求傳入你需要類(lèi)型的泛型)
class MyAdapter extends MyBaseAdapter<String> {
public MyAdapter(ArrayList<String> data) {
super(data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
//1, 加載布局文件
convertView = UIUtils.inflate(R.layout.list_item_home);
holder = new ViewHolder();
//2, 初始化控件 findViewById
holder.tv = (TextView) convertView.findViewById(R.id.tv);
//3, 打tag
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
String content = getItem(position);
holder.tv.setText(content);
return convertView;
}
}
ok,到了這里第一步封裝就完成了绝淡,以后的代碼中就省了不少重復(fù)的代碼宙刘。
第二步封裝
到了第二步,也是最難啃的骨頭牢酵,那就是對(duì)getView(...)進(jìn)行封裝悬包。相信大家也發(fā)現(xiàn)了getView(...)很臃腫,但它們填充的布局馍乙,還有ViewHolder又都不一樣布近,那怎么進(jìn)行封裝呢?相信仔細(xì)的童鞋發(fā)現(xiàn)了我在getView(...)中寫(xiě)了四個(gè)步驟
- 加載布局文件
- 初始化控件 findViewById
- 打tag
- 根據(jù)數(shù)據(jù)來(lái)刷新界面
接下來(lái)就圍繞這四部進(jìn)行封裝就可以了丝格。
新建一個(gè)BaseHolder類(lèi)
在BaseHolder中對(duì)這四個(gè)步驟進(jìn)行封裝
public abstract class BaseHolder<T> {
private View mRootView; //一個(gè)item布局
private T data;
public BaseHolder() {
mRootView = initView();
//3, 打tag
mRootView.setTag(this);
}
//1, 加載布局文件
//2, 初始化控件
public abstract View initView(); //具體布局交由子類(lèi)實(shí)現(xiàn)
//4, 根據(jù)數(shù)據(jù)刷新界面
public abstract void refreshData(T data); //具體數(shù)據(jù)由子類(lèi)提供
//item的布局對(duì)象
public View getView() {
return mRootView;
}
//設(shè)置item的數(shù)據(jù)
public void setData(T data) {
this.data = data;
refreshData(data);
}
//獲取item的數(shù)據(jù)
public T getData() {
return data;
}
}
這是運(yùn)用在我們的MyAdapter上撑瞧,在用的時(shí)候我們會(huì)發(fā)現(xiàn)BaseHolder是不能new的,這時(shí)候我們就需要在MyBaseAdapter中定義一個(gè)抽象方法getHolder()显蝌,交由子類(lèi)來(lái)實(shí)現(xiàn)
public View getView(int position, View convertView, ViewGroup parent) {
BaseHolder holder = getHolder();
if (convertView == null) {
//1, 加載布局文件
//2, 初始化控件 findViewById
//3, 打tag
holder = getHolder();
} else {
holder = (ViewHolder) convertView.getTag();
}
//4, 根據(jù)數(shù)據(jù)來(lái)刷新界面
holder.setData(getItem(position));
//return convertView; //這里不能直接返回convertView预伺,會(huì)出現(xiàn)空指針異常
return holder.getView();
}
public abstract BaseHolder getHolder(); //交由子類(lèi)來(lái)實(shí)現(xiàn)
進(jìn)行到了這一步相信大家也能發(fā)現(xiàn),我們必須在新建一個(gè)Holder繼承BaseHolder曼尊,確實(shí)如此(- -!)酬诀。
public class Holder extends BaseHolder<String> {
private TextView tvContent;
@Override
public View initView() {
// 1. 加載布局
//這時(shí)候你需要的填充你所需要的布局了
View view = UIUtils.inflate(R.layout.list_item_home);
// 2. 初始化控件
tvContent = (TextView) view.findViewById(R.id.tv_content);
return view;
}
@Override
public void refreshView(String data) { //string為前面的定義的泛型
tvContent.setText(data);
}
}
到了這一步就完全封裝好了÷嫫玻看下效果吧瞒御。
class Adapter extends MyBaseAdapter<String> {
public HomeAdapter(ArrayList<String> data) {
super(data);
}
@Override
public BaseHolder<String> getHolder() {
return new Holder();
}
}
這樣以后再寫(xiě)adapter簡(jiǎn)單的幾行就搞定了。
小結(jié)
在來(lái)簡(jiǎn)單的說(shuō)下流程吧艾船,要完成封裝我們需要些兩個(gè)基類(lèi)MyBaseAdapter和BaseHolder在兩個(gè)類(lèi)定義抽象方法葵腹,由子類(lèi)實(shí)現(xiàn)具體的操作便能完成對(duì)BaseAdapter的封裝。使用時(shí)也需要要定義2個(gè)類(lèi)繼承它們屿岂,即定義你自己的Holder和Adapter践宴,在其中實(shí)現(xiàn)邏輯,這樣可已減少在activity中使用adapter時(shí)的代碼量爷怀∽杓纾可能理解起來(lái)有點(diǎn)費(fèi)解,而且也可能會(huì)有人說(shuō)還不如不封裝,封裝了反而顯得的麻煩烤惊,但我相信在大型項(xiàng)目用起來(lái)效果應(yīng)該會(huì)比不封裝好一些乔煞。
ps:第一次寫(xiě)博客,可能有些地方考慮的不是很周到柒室,請(qǐng)大家見(jiàn)諒渡贾。就算沒(méi)人看,未來(lái)會(huì)堅(jiān)持下去雄右。當(dāng)做是自己的筆記和總結(jié)吧空骚!