android中繼承BaseAdapter實現DataAdapter通用數據適配器

試想下,數據適配器隻是提供不同的數據並匹配界面中的組件以呈現不同的數據內容.那麼就可以對界面組件與數據項入手進行修改.

通常在BaseAdapter.getView中會使用ViewHolder方式來緩存界面中的組件,以便提高性能.那我們可以定義一個DataViewHolder類

[java]  

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方法中獲取該組件實例.

[java] 

public int[] getFindViewByIDs() {  

            return new int[]{  

                R.id.ItemText,   

                R.id.ItemImage  

            };  

        }  

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

[java]  

public View getLayout(int position, DataViewHolder vh) {  

            return inflater.inflate(R.layout.gv_content, null);  

        }  

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

[java]  

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方法如下

[java]  

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(…);  

        }  

 

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

[java]  

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

[java]  

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,則 

[java] 

class StrAdapter extends DataAdapter<String>{}  

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

發佈留言