1. 程式人生 > >利用Android反射與泛型機制寫一個通用的Adapter類

利用Android反射與泛型機制寫一個通用的Adapter類

注意點:Android的反射機制有一個問題,就是Class.getDeclaredFields()返回的變數陣列與我們定義的類的變數順序是不一致的.Android是經過了字母順序排序的.所以我們需要將變數名傳入adapter

//定義一個帶泛型的抽象類作為基類,T表示資料類,E表示ViewHolder類
public abstract class TBaseAdapter<T> extends BaseAdapter{
    List<T> mList;//用於存放資料集
    LayoutInflater mInflater;
    Context context;
    int [] viewIds;//存放控制元件ID
    String[] fields;//存放ViewHolder類變數的名字
    int layoutId;//佈局檔案ID
    Class<?> classOfE;//ViewHolder類
    //建構函式
    public TBaseAdapter(Context context, List<T> mList) {
    // TODO Auto-generated constructor stub
        mInflater = LayoutInflater.from(context);
        this.mList = mList;
        this.context = context;
    }
    public void setFields(String[] fields) {
        this.fields = fields;
    }
    public void setViewIds(int[] viewIds){
        this.viewIds = viewIds;
    }
    public void setClass(Class<?> e){
        this.classOfE = e;
    }
    public void setLayoutId(int layoutId) {
        this.layoutId = layoutId;
    }
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return mList == null ? 0 : mList.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    //獲取佈局檔案,將控制元件初始化
    public Object initViewHolder(View convertView){

        try {
            if (fields.length != viewIds.length) {
                return null;
            }
            Object e = classOfE.newInstance();//呼叫空建構函式
            int length = fields.length;
            for(int i = 0;i<length;i++){
                Field field = classOfE.getDeclaredField(fields[i]);//通過反射獲取變數
                field.setAccessible(true);//將變數設定為可訪問狀態
                field.set(e,convertView.findViewById(viewIds[i]));//為變數設值
            }
            return e;
        } catch (InstantiationException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
            return null;
        } catch (IllegalAccessException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
            return null;
        } catch (IllegalArgumentException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
            return null;
        } catch (NoSuchFieldException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return null;
        }
    }
    //抽象方法,實現些方法用於數集的繫結
    public abstract void addDataToView(T t,Object o);
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        Object e = null;
        if (convertView == null) {
        convertView = mInflater.inflate(layoutId, null);
        e =initViewHolder(convertView);
        if (e!=null)
            convertView.setTag(e);

        } else
            e = convertView.getTag();
        addDataToView(mList.get(position),e);
        return convertView;
    }
}

這樣以後寫Adapter的時候,只要繼承這個類,並實現addDataToView()方法就可以.然初始化adapter後,傳入相應的佈局檔案ID,控制元件ID,變數名和ViewHolder類就可以.如下:
Adapter adapter = new Adapter(this, mList);
adapter.setLayoutId(R.layout.item);
int[] ids = {R.id.name,R.id.age,R.id.sex};
String[] fields = {“name”,”age”,”sex”};
adapter.setClass(MyViewHolder.class);
adapter.setViewIds(ids);
adapter.setFields(fields);