当前位置: 代码迷 >> Android >> android中承继BaseAdapter实现DataAdapter通用数据适配器
  详细解决方案

android中承继BaseAdapter实现DataAdapter通用数据适配器

热度:89   发布时间:2016-04-28 08:03:00.0
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中使用.目前就可以基本使用满足通用性.



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

      

  相关解决方案