原文出处:http://blog.csdn.net/javasuki/article/details/11869615
说明:为了便于以后拿来就用,在作者的基础上进行了代码修复和补充
试想下,数据适配器只是提供不同的数据并匹配界面中的组件以呈现不同的数据内容.那么就可以对界面组件与数据项入手进行修改.
通常在BaseAdapter.getView中会使用ViewHolder方式来缓存界面中的组件,以便提高性能.那我们可以定义一个DataViewHolder类
- public class DataViewHolder {
- HashMap<Integer,View> mapView = new HashMap<Integer,View>();
- HashMap<String,Object> mapData = new HashMap<String,Object>();
- public void setView(int key,View v){
- this.mapView.put(key, v);
- }
- @SuppressWarnings("unchecked")
- public <T> T getView(int key){
- return (T)this.mapView.get(key);
- }
- @SuppressWarnings("unchecked")
- public <T> T getView(Class<T> clazz, int key){
- return (T)this.mapView.get(key);
- }
- public void setData(String key, Object value){
- mapData.put(key, value);
- }
- @SuppressWarnings("unchecked")
- public <T> T getData(String key){
- return (T)mapData.get(key);
- }
- @SuppressWarnings("unchecked")
- public <T> T getData(Class<T> clazz, String key){
- return (T)mapData.get(key);
- }
- }
- public int[] getFindViewByIDs() {
- return new int[]{
- R.id.ItemText,
- R.id.ItemImage
- };
- }
- public View getLayout(int position, DataViewHolder vh) {
- return inflater.inflate(R.layout.gv_content, null);
- }
- public View getView(int position, View convertView, ViewGroup parent) {
- DataViewHolder vh;
- if(convertView == null){
- vh = new DataViewHolder();
- convertView = this.getLayout(position,vh); //获取布局资源
- if(convertView == null) {
- return null;
- }
- int[] idAry = this.getFindViewByIDs(); //获取界面组件
- if(idAry == null) {
- idAry = new int[]{};
- }
- for(int id : idAry){
- vh.setView(id, convertView.findViewById(id)); //资源id作为key,缓存界面中的组件
- }
- convertView.setTag(vh);
- }
- else {
- vh = (DataViewHolder)convertView.getTag();
- }
- this.renderData(position, vh); //继承类中的方法,完成数据到界面组件的赋值
- return convertView;
- }
对数据项入手时,我们只需要定义泛型参数来支持,先暂时定义为HashMap<String,String>, renderData方法如下
- public void renderData(int position, DataViewHolder vh) {
- HashMap<String,String> map = (HashMap<String,String>)this.getItem(position);
- vh.getView(TextView.class, R.id.ItemText).setText(map.get("title"));
- ImageView imgView = vh.getView(R.id.ItemImage);
- imgView.setImageURI(...);
- }
让我们来看一下完整的实现
要首先在layout中定义一个list_view.xml布局文件,如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ListView
android:scrollbars="none"
android:id="@+id/lv_list_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dip"
android:paddingLeft="12dip"
android:paddingRight="12dip" >
<ImageView
android:id="@+id/ItemImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingTop="12dip" />
<TextView
android:id="@+id/ItemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ItemImage"
android:text="TextView02" />
</RelativeLayout>
定义一个DataViewHolder的类
import java.util.HashMap;
import android.view.View;
public class DataViewHolder {
HashMap<Integer,View> mapView = new HashMap<Integer,View>();
HashMap<String,Object> mapData = new HashMap<String,Object>();
public void setView(int key,View v){
this.mapView.put(key, v);
}
@SuppressWarnings("unchecked")
public <T> T getView(int key){
return (T)this.mapView.get(key);
}
@SuppressWarnings("unchecked")
public <T> T getView(Class<T> clazz, int key){
return (T)this.mapView.get(key);
}
public void setData(String key, Object value){
mapData.put(key, value);
}
@SuppressWarnings("unchecked")
public <T> T getData(String key){
return (T)mapData.get(key);
}
@SuppressWarnings("unchecked")
public <T> T getData(Class<T> clazz, String key){
return (T)mapData.get(key);
}
}
定义一个DataAdapter的类继承BaseAdapter,实现自定义通用适配
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public abstract class DataAdapter<TItem> extends BaseAdapter {
protected LayoutInflater inflater = null;
protected Context mContext;
private List<TItem> lst;
public DataAdapter(Context c, List<TItem> lst) {
this.mContext = c;
this.lst = lst;
this.inflater = LayoutInflater.from(c);
}
@Override
public int getCount() {
return lst.size();
}
public void insert(TItem data) {
lst.add(0, data);
this.notifyDataSetChanged();
}
public void append(TItem data) {
lst.add(data);
this.notifyDataSetChanged();
}
public void replace(TItem data) {
int idx = this.lst.indexOf(data);
this.replace(idx, data);
}
public void replace(int index, TItem data) {
if (index < 0) {
return;
}
if (index > lst.size() - 1) {
return;
}
lst.set(index, data);
this.notifyDataSetChanged();
}
public List<TItem> getItems() {
return lst;
}
@Override
public Object getItem(int position) {
return lst.get(position);
}
public TItem getItemT(int position) {
return lst.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public void removeItem(int position) {
if (lst.size() <= 0) {
return;
}
if (position < 0) {
return;
}
if (position > lst.size() - 1) {
return;
}
lst.remove(position);
this.notifyDataSetChanged();
}
public void clear() {
lst.clear();
this.notifyDataSetChanged();
}
public abstract int[] getFindViewByIDs();
public abstract View getLayout(int position, DataViewHolder vh);
public final View getResourceView(int id) {
return inflater.inflate(id, null);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
DataViewHolder vh;
if (convertView == null) {
vh = new DataViewHolder();
convertView = this.getLayout(position, vh);
if (convertView == null) {
return null;
}
int[] idAry = this.getFindViewByIDs();
if (idAry == null) {
idAry = new int[] {};
}
for (int id : idAry) {
vh.setView(id, convertView.findViewById(id));
}
convertView.setTag(vh);
} else {
vh = (DataViewHolder) convertView.getTag();
}
this.renderData(position, vh);
return convertView;
}
public abstract void renderData(int position, DataViewHolder vh);
}
实际使用,如何使用DataAdapter类呢?我们还是要继承来实现,如果要实现条目的点击事件,需要实现OnItemClick接口
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnItemClickListener{
//为了避免发生类型转化错误,HashMap中的值推荐使用Object类型
private List<HashMap<String, Object>> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_view);
list = new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < 20; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("title", "标题"+i);
map.put("image", R.drawable.ic_launcher + "");
list.add((HashMap<String, Object>) map);
}
PrgmAdapter adapter = new PrgmAdapter(MainActivity.this, list);// 实例化数据适配器
ListView lv_list_view1 = (ListView) findViewById(R.id.lv_list_view);
lv_list_view1.setAdapter(adapter);
lv_list_view1.setOnItemClickListener(this);
}
private class PrgmAdapter extends DataAdapter<HashMap<String, Object>> {
public PrgmAdapter(Context c, List<HashMap<String, Object>> lst) {
super(c, lst);
}
@Override
public int[] getFindViewByIDs() {
return new int[] { R.id.ItemImage, R.id.ItemText };
}
@Override
public View getLayout(int position, DataViewHolder vh) {
return this.getResourceView(R.layout.list_view_item);
}
@Override
public void renderData(int position, DataViewHolder vh) {
HashMap<String, Object> map = this.getItemT(position);
vh.getView(TextView.class, R.id.ItemText).setText(map.get("title").toString());
vh.getView(ImageView.class, R.id.ItemImage).setImageResource(
Integer.parseInt(map.get("image").toString()));
}
}
@Override
public void onItemClick(AdapterView<?> adapterview, View view, int i, long l) {
Toast.makeText(MainActivity.this, "你选中了:"+list.get(i).get("title"), 1).show();
}
}
如果其他类型,例如String,则
- class StrAdapter extends DataAdapter<String>{}
完全可以再进行调整,比如设置资源ID提供一个方法,在getView中使用.目前就可以基本使用满足通用性.
贴图:(都是使用上面定义的适配器)