ListView是App開發中最常見的控件之一了,與之相隨的則是BaseAdapter的使用,BaseAdapter的作用則是爲我們的ListView提供數據源,普通的用法相信大家都會用,今天主要說明一下,列表中如果有多種樣式的ItemView時,應該如何去高效的加載.
先看一下效果圖:
如圖所示:整個列表中存在着兩種樣式的ItemView,開始用傳統的ConvertView去緩存子項時,發現兩種佈局一滑動就出現了錯亂,後來爲了項目進度,看到沒有發生內存溢出後就沒有用ConvertView做子View的緩存,今天在翻看Adapter及其子類的源碼時發現,如下代碼,瞬間想到之前沒有對多佈局多緩存的問題,於是上網查看了一下,果然就是用這幾個方法去實現,代碼如下:
public interface Adapter {
void registerDataSetObserver(DataSetObserver observer);
void unregisterDataSetObserver(DataSetObserver observer);
int getCount();
Object getItem(int position);
long getItemId(int position);
boolean hasStableIds();
View getView(int position, View convertView, ViewGroup parent);
static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
int getItemViewType(int position); <span style="font-size:24px;"> <span style="color:#FF0000;">//方法一,得到佈局類型 </span></span>
int getViewTypeCount(); <span style="font-size:24px;color:#FF0000;"> // 方法二,得到佈局總</span>
static final int NO_SELECTION = Integer.MIN_VALUE;
/**
* @return true if this adapter doesn't contain any data. This is used to determine
* whether the empty view should be displayed. A typical implementation will return
* getCount() == 0 but since getCount() includes the headers and footers, specialized
* adapters might want a different behavior.
*/
boolean isEmpty();
}
就是紅色註釋出的兩個方法,而BaseAdapter已經幫我們提供了默認的實現,才使得我們沒有關注到這兩個方法,BaseAdapter的默認實現如下:
package android.widget;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public boolean hasStableIds() {
return false;
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
public boolean areAllItemsEnabled() {
return true;
}
public boolean isEnabled(int position) {
return true;
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
<span style="color:#FF0000;"> public int getItemViewType(int position) {
return 0;
}</span>
<span style="color:#FF0000;">public int getViewTypeCount() {
return 1;
}</span>
public boolean isEmpty() {
return getCount() == 0;
}
}
有了這兩個方法後,我們只需重寫這兩個方法即可,下面是我重寫的Adapter代碼:
<span style="font-size:18px;">/**********************************************************
* @文件名稱:CountryListAdapter.java
* @文件作者:rzq
* @創建時間:2014年7月22日 下午2:33:43
* @文件描述:國家列表適配器
* @修改歷史:2014年7月22日創建初始版本
**********************************************************/
public class CountryListAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<Country> dataList;
private Country country;
private ViewHolder holder1;
private ViewHolder holder2;
public CountryListAdapter(Context context, ArrayList<Country> dataList) {
this.mContext = context;
this.dataList = dataList;
}
@Override
public int getCount() {
return dataList.size();
}
@Override
public Object getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
country = (Country) dataList.get(position);
int type = getItemViewType(position);
if (convertView == null) {
switch (type) {
case 0:
holder1 = new ViewHolder();
convertView = LayoutInflater.from(mContext)
.inflate(R.layout.catagories_expandlistview_group,
parent, false);
holder1.textView = (TextView) convertView
.findViewById(R.id.catagories_group_textview);
convertView.setTag(holder1);
break;
case 1:
holder2 = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(
R.layout.register_expandlistview_child, parent, false);
holder2.textView = (TextView) convertView
.findViewById(R.id.register_child_textview);
holder2.imageView = (ImageView) convertView
.findViewById(R.id.register_country_flag);
convertView.setTag(holder2);
break;
}
} else {
switch (type) {
case 0:
holder1 = (ViewHolder) convertView.getTag();
break;
case 1:
holder2 = (ViewHolder) convertView.getTag();
break;
}
}
switch (type) {
case 0:
holder1.textView.setText(country.getIndexChar());
break;
case 1:
holder2.textView.setText(country.getCountryName());
holder2.imageView.setImageDrawable(country.getFlagDrawable());
break;
}
return convertView;
}
@Override
public int getItemViewType(int position) {
country = (Country) getItem(position);
if (country.isGroup()) {
return 0;
} else {
return 1;
}
}
@Override
public int getViewTypeCount() {
return 2;
}
private static class ViewHolder {
private TextView textView;
private ImageView imageView;
}
}</span>
這樣確保了內存不會溢出.也可以提高ListView的加載效率.