android开发之继承BaseAdapter实现通用数据适配器

来源:互联网 发布:剑三初始捏脸数据 编辑:程序博客网 时间:2024/05/21 07:14

原文出处:http://blog.csdn.net/javasuki/article/details/11869615


说明:为了便于以后拿来就用,在作者的基础上进行了代码修复和补充


试想下,数据适配器只是提供不同的数据并匹配界面中的组件以呈现不同的数据内容.那么就可以对界面组件与数据项入手进行修改.

通常在BaseAdapter.getView中会使用ViewHolder方式来缓存界面中的组件,以便提高性能.那我们可以定义一个DataViewHolder类

[java] view plaincopyprint?
  1. public class DataViewHolder {  
  2.   
  3.     HashMap<Integer,View> mapView = new HashMap<Integer,View>();  
  4.     HashMap<String,Object> mapData = new HashMap<String,Object>();  
  5.     public void setView(int key,View v){  
  6.         this.mapView.put(key, v);  
  7.     }  
  8.       
  9.     @SuppressWarnings("unchecked")  
  10.     public <T> T getView(int key){  
  11.         return (T)this.mapView.get(key);  
  12.     }  
  13.       
  14.     @SuppressWarnings("unchecked")  
  15.     public <T> T getView(Class<T> clazz, int key){  
  16.         return (T)this.mapView.get(key);  
  17.     }  
  18.       
  19.       
  20.     public void setData(String key, Object value){  
  21.         mapData.put(key, value);  
  22.     }  
  23.       
  24.     @SuppressWarnings("unchecked")  
  25.     public <T> T getData(String key){  
  26.         return (T)mapData.get(key);  
  27.     }  
  28.       
  29.     @SuppressWarnings("unchecked")  
  30.     public <T> T getData(Class<T> clazz, String key){  
  31.         return (T)mapData.get(key);  
  32.     }  
  33. }  
对界面组件入手时,我们需要一个方法来提供一组界面组件的ID号,便于在BaseAdapter.getView方法中获取该组件实例.

[java] view plaincopyprint?
  1. public int[] getFindViewByIDs() {  
  2.             return new int[]{  
  3.                 R.id.ItemText,   
  4.                 R.id.ItemImage  
  5.             };  
  6.         }  
在实现BaseAdapter.getView方法时,通常需要获取布局资源,那么我们提供一个方法

[java] view plaincopyprint?
  1. public View getLayout(int position, DataViewHolder vh) {  
  2.             return inflater.inflate(R.layout.gv_content, null);  
  3.         }  
以便在BaseAdapter.getView方法中调用,我们来实现BaseAdapter.getView方法

[java] view plaincopyprint?
  1. public View getView(int position, View convertView, ViewGroup parent) {  
  2.         DataViewHolder vh;  
  3.         if(convertView == null){  
  4.             vh = new DataViewHolder();  
  5.             convertView = this.getLayout(position,vh); //获取布局资源  
  6.             if(convertView == null)  {
  7.  return null;  
  8.     } 
  9.             int[] idAry = this.getFindViewByIDs(); //获取界面组件  
  10.             if(idAry == null) {
  11. idAry = new int[]{};  
  12.     }
  13.             for(int id : idAry){  
  14.                 vh.setView(id, convertView.findViewById(id)); //资源id作为key,缓存界面中的组件  
  15.             }  
  16.             convertView.setTag(vh);  
  17.         }  
  18.         else {
  19.      vh = (DataViewHolder)convertView.getTag();  
  20. }
  21.         this.renderData(position, vh); //继承类中的方法,完成数据到界面组件的赋值  
  22.         return convertView;  
  23.     }  


对数据项入手时,我们只需要定义泛型参数来支持,先暂时定义为HashMap<String,String>, renderData方法如下

[java] view plaincopyprint?
  1. public void renderData(int position, DataViewHolder vh) {  
  2.             HashMap<String,String> map = (HashMap<String,String>)this.getItem(position);  
  3.             vh.getView(TextView.class, R.id.ItemText).setText(map.get("title"));      
  4.             ImageView imgView = vh.getView(R.id.ItemImage);   
  5.             imgView.setImageURI(...);  
  6.         }  

让我们来看一下完整的实现

要首先在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>


然后定义一个list_view_item的条目布局文件 list_view_item.xml
<?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);}@Overridepublic 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;}@Overridepublic Object getItem(int position) {return lst.get(position);}public TItem getItemT(int position) {return lst.get(position);}@Overridepublic 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);}@Overridepublic 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;@Overrideprotected 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);}@Overridepublic int[] getFindViewByIDs() {return new int[] { R.id.ItemImage, R.id.ItemText };}@Overridepublic View getLayout(int position, DataViewHolder vh) {return this.getResourceView(R.layout.list_view_item);}@Overridepublic 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()));}}@Overridepublic void onItemClick(AdapterView<?> adapterview, View view, int i, long l) {Toast.makeText(MainActivity.this, "你选中了:"+list.get(i).get("title"), 1).show();}}


如果其他类型,例如String,则 
[java] view plaincopyprint?
  1. class StrAdapter extends DataAdapter<String>{}  

完全可以再进行调整,比如设置资源ID提供一个方法,在getView中使用.目前就可以基本使用满足通用性.



贴图:(都是使用上面定义的适配器)

      


0 0