天天看點

對RecyclerView的Adapter進行抽取

當項目當中遇到了很多個頁面都要用到清單的時候,我們可能會用到ListView又或者用到RecyclerView,其實不管用到哪個控件來實作,adapter和hodler是必須要用到的,每寫一個ListView或者RecyclerView,都要去實作一個adapter和hodler,顯然有很多重複的代碼,那麼能不能把共有的方法抽取出來呢,顯然是可以的,ListView的抽取以前寫過,位址是: http://blog.csdn.net/ming_147/article/details/62892727,這邊文章主要是叙述RecyclerView的抽取。

RecyclerView的Adapter是繼承于RecyclerView.Adapter<BaseAdapter.ViewHolder>,ViewHolder在這裡我是以泛型的形式引入進來,并在BaseAdapter類中具體實作,如下:

public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.ViewHolder>{
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
}      

好了,具體就這些方法,那麼該如何去下手呢,我們可以先分析一下,要實作一個Adapter,我們都需要哪些條件呢?首先資料是必不可少的,一般是以集合的形式傳入,這裡我們可以從構造方法裡傳進,集合确定,而類型不能确定,我們可以用D來辨別,執行個體變量攜帶泛型,記得給類也加上泛型,這裡我寫了一個空的接口,用來做雙向綁定,如下:

public class BaseAdapter<D extends IModel> extends RecyclerView.Adapter<BaseAdapter.ViewHolder> {
    private List<D> dataList;

    public BaseAdapter(List<D> dataList) {
        this.dataList = dataList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
}      

資料傳入了,那麼還少什麼呢,對,View視圖,這裡我把BaseAdapter改成了抽象類,并實作擷取view的一個抽象方法,并在onCreateViewHolder方法裡進行使用,如下:

public abstract int getLayoutId();

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(),parent,false);
    BaseAdapter.ViewHolder vh = new BaseAdapter.ViewHolder(view);
    return vh;
}      

接下來,就是向外繼續抽象一個方法,用于資料的綁定,其實就是把onBindViewHolder方法,抽象到外面自己來實作其裡面的功能:

public abstract void createHolder(BaseAdapter.ViewHolder holder, D d);

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        createHolder(holder,dataList.get(position));
    }      

目前為止,adapter裡已經抽取完成,下面看下ViewHolder裡,其實在ViewHolder裡,主要用于擷取控件:

public static class ViewHolder extends RecyclerView.ViewHolder {
        private View rootView;
        private SparseArray<View> views=new SparseArray<>();
        public ViewHolder(View itemView) {
            super(itemView);
        }
        public <T extends View> T get(int id){
            T view=(T)views.get(id);
            if(view==null){
                view=(T)rootView.findViewById(id);
                views.put(id,view);
            }
            return view;
        }
        //TextView設定資料
        public void setText(int viewId, String txt) {
            TextView mTextView = get(viewId);
            mTextView.setText(txt);
        }
        //設定圖檔
        public void setPic(int viewId, String url) {
            ImageView mImageView = get(viewId);
            Picasso.with(mContext).load(url).fit().error(R.drawable.ic_launcher).placeholder(mImageView.getDrawable()).memoryPolicy(MemoryPolicy.NO_CACHE).into(mImageView);
        }
    }      

這裡我寫了兩個方法setText和setPic,主要目的就是簡便我們的代碼,友善我們調用,到這裡,我們這個BaseAdapter,已經抽取完成了,下面看一下整個類:

/**
 * Created by AbnerMing on 2017/12/29.
 */

public abstract class BaseAdapter<D extends IModel> extends RecyclerView.Adapter<BaseAdapter.ViewHolder> {
    private List<D> dataList;

    public abstract int getLayoutId();

    public BaseAdapter(List<D> dataList) {
        this.dataList = dataList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(),parent,false);
        BaseAdapter.ViewHolder vh = new BaseAdapter.ViewHolder(view);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        createHolder(holder,dataList.get(position));
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public abstract void createHolder(BaseAdapter.ViewHolder holder, D d);

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private View rootView;
        private SparseArray<View> views=new SparseArray<>();
        public ViewHolder(View itemView) {
            super(itemView);
        }
        public <T extends View> T get(int id){
            T view=(T)views.get(id);
            if(view==null){
                view=(T)rootView.findViewById(id);
                views.put(id,view);
            }
            return view;
        }
        //TextView設定資料
        public void setText(int viewId, String txt) {
            TextView mTextView = get(viewId);
            mTextView.setText(txt);
        }
        //設定圖檔
        public void setPic(int viewId, String url) {
            ImageView mImageView = get(viewId);
            Picasso.with(mContext).load(url).fit().error(R.drawable.ic_launcher).placeholder(mImageView.getDrawable()).memoryPolicy(MemoryPolicy.NO_CACHE).into(mImageView);
        }
    }
}      

具體調用:

public class MyAdapter extends BaseAdapter<Bean>{
    public MyAdapter(List<Bean> dataList) {
        super(dataList);
    }

    @Override
    public int getLayoutId() {
        return 0;
    }

    @Override
    public void createHolder(BaseAdapter.ViewHolder holder, Bean bean) {

    }
}      

以後所有的Adapter都可以去繼承BaseAdapter,隻僅僅的實作兩個方法就ok了,是不是友善多了。