天天看點

android中繼承BaseAdapter實作DataAdapter通用資料擴充卡

試想下,資料擴充卡隻是提供不同的資料并比對界面中的元件以呈現不同的資料内容.那麼就可以對界面元件與資料項入手進行修改.

通常在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);
	}
}
           

對界面元件入手時,我們需要一個方法來提供一組界面元件的ID号,便于在BaseAdapter.getView方法中擷取該元件執行個體.

public int[] getFindViewByIDs() {
			return new int[]{
				R.id.ItemText, 
				R.id.ItemImage
			};
		}
           

在實作BaseAdapter.getView方法時,通常需要擷取布局資源,那麼我們提供一個方法

public View getLayout(int position, DataViewHolder vh) {
			return inflater.inflate(R.layout.gv_content, null);
		}
           

以便在BaseAdapter.getView方法中調用,我們來實作BaseAdapter.getView方法

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(...);
		}
           

讓我們來看一下完整的實作

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類呢?我們還是要繼承來實作.

public class T1Activity extends Activity {
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_t1);

		HashMap<String,String> map1 = new HashMap<String,String>();
		map1.put("title","xxx");
		map1.put("url","xxx");
		...
		
		List<HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();
		al.add(map1); //添加資料
		al.add(map2); //添加資料
		...

		PrgmAdapter adapter = new PrgmAdapter(T1Activity.this, al); //執行個體化資料擴充卡
		GridView gridview=(GridView)findViewById(R.id.gridView1);
		gridview.setAdapter(adapter);
	}

	//實際使用要繼承來實作.現在我們不需要關心getView方法了(除非有特殊需求),隻需要提供布局資源,元件資源号,并在renderData中完成指派就OK了.
	private class PrgmAdapter extends DataAdapter<HashMap<String,String>>{
		public PrgmAdapter(Context c, List<HashMap<String,String>> lst){
			super(c,lst);
		}
		
		@Override
		public int[] getFindViewByIDs() {
			return new int[]{
				R.id.ItemText, 
				R.id.ItemImage
			};
		}
		
		@Override
		public View getLayout(int position, DataViewHolder vh) {
			return this.getResourceView(R.layout.gv_content);
		}
		
		@Override
		public void renderData(int position, DataViewHolder vh) {
			HashMap<String,String> map = this.getItemT(position);
			vh.getView(TextView.class, R.id.ItemText).setText(map.get("title"));	
			ImageView imgView = vh.getView(R.id.ItemImage);	
			...
		}
	}
}
           

如果其他類型,例如String,則 

class StrAdapter extends DataAdapter<String>{}
           

完全可以再進行調整,比如設定資源ID提供一個方法,在getView中使用.目前就可以基本使用滿足通用性.

貼圖:(都是使用上面定義的擴充卡)

android中繼承BaseAdapter實作DataAdapter通用資料擴充卡
android中繼承BaseAdapter實作DataAdapter通用資料擴充卡
android中繼承BaseAdapter實作DataAdapter通用資料擴充卡