RecyclerView.Adapter的封裝,理解封裝的過程

版權聲明:本文出自阿鐘的博客,出處:http://blog.csdn.net/a_zhon/。


這一節我們來講一下RecyclerView.Adapter的簡易封裝,相信大家都會經常逛開源平臺或者社區每每看到好多大神分享的乾貨寫的那麼叼CV之後即可直接使用是不是非常開心?那你有沒有想過自己也可以來造一個輪子讓別人也來使用你造的呢?下面我們就開始造輪子吧(重在封裝的過程,對封裝的理解)。

一: 我們先來看下默認的Adapter長啥樣

public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.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 class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

從上面代碼中可以看出要寫出一個RecyclerView.Adapter必須自己寫一個ViewHolder且一定要繼承RecyclerView.ViewHolder;然後重寫onCreateViewHolderonBindViewHoldergetItemCount這三個函數,然而我們最關心的也就是onBindViewHolder函數對數據進行綁定。 而其他幾個函數都基本上都是固定格式了,所以我們就可以將這些千篇一律的代碼進行封裝了。Adapter中我們最終要的一個就是數據源了,所以我們需要先定義我們的數據源但是你會發現在不同的地方 我們的數據也是不一樣的那我們怎麼定義呢?這個時候我們就需要引入泛型了。

 /**
  * 泛型:廣泛的類型
  * 在編寫代碼的過程中,使用集合強轉的時候可能會出現ClassCastException(類型轉換異常)
  * 因爲在集合中存放的對象是任意的,使用對象的時候會有安全隱患
  * JDK1.5之後出現了泛型
  * 1.泛型好處在於:將程序運行時的異常轉換成編譯時的異常
  *                方便程序員編寫代碼,提高代碼的安全性
  * 2.避免了強轉操作
  * 泛型的格式:<類型>
  * 泛型的使用:在集合中使用的比較多,其實泛型的定義就是指定接收某一類型
  * 
  * 泛型出現之前與出現之後的對比:
  * 早期:定義Object去接收未知類型
  * 現在:當需要使用的引用數據類型不確定的時候,使用泛型去作爲一個規則去接收數據(提高代碼的擴展性)
  *          一旦這麼定義,該類中所有使用到了該泛型的方法都必須遵守這個規則
  * 現在我想打破這個規則:
  * 1.之前都是泛型類
  * 2.可以使用泛型方法打破這個規則
  * 當方法需要使用未知類型的引用數據的時候,如果在類上定義泛型,會造成使用的侷限性,爲了打破這個侷限性,
  * 我們在方法中單獨定義泛型,讓該方法使用的泛型脫離類的控制
  * 格式:修飾符 <泛型> 返回值 方法名(){}
  * 靜態方法使用泛型:必須使用自己定義的泛型
  * 
  * 泛型的高級應用:
  * 佔位符:  ?
  * 泛型限定: ? extends Person 定義上限,向下擴展
  *      : ? super Person  定義下限,向上延伸
  * 
  */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

二: 可以看出下面出現的D(是一個實體類)和VH分別代表了我們的數據源、視圖管理者,這樣我們封裝的時候就可以用來當作真實數據操作了。

public abstract class BaseRecyclerAdapter<D, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

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

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

    }

    @Override
    public int getItemCount() {
        return 0;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這裏還需要一個ViewHolder我們來寫一個BaseViewHolder

 class BaseViewHolder extends RecyclerView.ViewHolder {
        public BaseViewHolder(View itemView) {
            super(itemView);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

三: 現在我們就可以來實現Adapter裏面的邏輯了,寫一個構造函數用來初始化數據源和佈局id同時寫一個抽象方法(這也就是爲什麼好多Base都是抽象類了)用來顯示數據

public abstract class BaseRecyclerAdapter<D, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
    /**
     * 數據源
     */
    private List<D> data;
    /**
     * 佈局資源id
     */
    private int layoutResId;

    public BaseRecyclerAdapter(int layoutResId, List<D> data) {
        this.data = data == null ? new ArrayList<D>() : data;
        if (layoutResId != 0) {
            this.layoutResId = layoutResId;
        } else {
            throw new NullPointerException("請設置Item資源id");
        }
    }

    @Override
    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false);
        return (VH) new BaseViewHolder(view);
    }

    @Override
    public void onBindViewHolder(VH holder, int position) {
        bindTheData(holder, data.get(position));
    }

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

    /**
     * 綁定數據
     *
     * @param holder 視圖管理者
     * @param data   數據源
     */
    protected abstract void bindTheData(VH holder, D data);

    class BaseViewHolder extends RecyclerView.ViewHolder {
        public BaseViewHolder(View itemView) {
            super(itemView);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

四: 封裝了這麼多我們寫一個適配器試驗一下

public class TestAdapter extends BaseRecyclerAdapter<DataBean, BaseRecyclerAdapter.BaseViewHolder> {

    public TestAdapter(int layoutResId, List<DataBean> data) {
        super(layoutResId, data);
    }

    @Override
    protected void bindTheData(BaseViewHolder holder, DataBean data) {

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到我們在實現一個適配器就只需要實現一個構造函數和一個綁定數據了是不是簡便多了,當然到現在我們的BaseViewHolder還是 
有問題的同意需要將他封裝一下

class BaseViewHolder extends RecyclerView.ViewHolder {
    /**
     * 集合類,layout裏包含的View,以view的id作爲key,value是view對象
     */
    private SparseArray<View> mViews;

    public BaseViewHolder(View itemView) {
        super(itemView);
        mViews = new SparseArray<>();
    }

    public <T extends View> T findViewById(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = itemView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }
    /**
     * 設置文本資源
     *
     * @param viewId view id
     * @param s      字符
     */
    public TextView setText(int viewId, CharSequence s) {
        TextView view = findViewById(viewId);
        view.setText(s);
        return view;
    }
    //......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

從上面代碼可以看出使用了SparseArray(這個和HashMap用法是一致的,Google對HashMap的一個加強版)用來保存已經找過的view,這裏也是很簡單的封裝但確非常的實用只需要一個id便可以做你想做的事,後續有時間將繼續封裝上拉、下拉操作;




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章