利用databinding快速實現(xiàn)RecyclerView的adapter,支持多種item

閱讀這篇筆記你需要了解安卓的數據綁定框架databinding
首先貼上校長看到的感覺寫得最好的兩篇 介紹databinding的文章:
1. CornorLin:Android Data Binding 系列(一) -- 詳細介紹與使用
2. QQ音樂技術團隊:Android DataBinding 數據綁定

不管作為一名安卓還是android程序猿,總是少不了一直沒完沒了的重復制造adapter,viewholder,就像


Paste_Image.png

等等,啊喂,這根本是同一個類呀!哦不好意思,實在太像了,搞錯了,真實的情況是這樣的:

Paste_Image.png

這簡直可以做一個找茬游戲了,整天在這弄重復的代碼,不禁要想,除了那些骯臟(滑稽)的大洋我們整天這樣圖的是什么。作為一名有追求的立志成為一名架構師,從來懶得多寫代碼的程序猿這樣的情況怎么能忍!
于是不禁讓人想我們寫這些代碼屎味的什么?

Adapter與ViewHolder的作用:
  • ViewHolder是用來通過findviewById來存放item對應的layout里邊的View控件的,
  • AdapteronCreateViewHolder(ViewGroup parent, int viewType)方法負責將獲取將ViewHolder取出;void onBindViewHolder(BindingHolder holder, int position)負責將實體類的內容一條一條的通過set方法顯示到對應的界面上。
再看看databinding的作用:
  • 通過DatabindingUtils的public static <T extends ViewDataBinding> T inflate(LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent, boolean attachToParent)方法獲取一個ViewDataBinding,包含了Layout中所有的控件;
  • boolean setVariable(int variableId, Object value)負責將數據與界面綁定自動完成類似textview.setText(item.text)這樣的工作,

是不是感覺職能高度重合呢,而且databinding好像用起來更省力,那是不是可以利用ViewDataBinding 替代ViewHoldr里邊的沒完沒了的findViewById呢,能不能用一個boolean setVariable(int variableId, Object value)來替代onBindViewHolder(BindingHolder holder, int position)中沒完沒了的set房呢。答案是可以的

現(xiàn)在假定你已經閱讀過那兩篇文章,對于databinding有了一定的理解。先上demo的代碼地址
先看一下效果圖:

Paste_Image.png

可以看出來在demo中有三種item,按照以前的慣例。我們需要三個Adapter,三個ViewHolder,三個實體Bean,三個layout文件。但是呢,讓我們看一下demode代碼結構

Paste_Image.png

三個實體bean,三個layout,但是只有一個Adapter,里邊有一個ViewHolder。但是實現(xiàn)了三種item的效果好神奇吧,并且即使我想再加一種item,只需要添加一個實體Bean,再加一個layout文件就好了不用去寫什么ViewHolder跟Adapter了,哈哈神奇吧。

首先看看我們是怎么用的吧:

 List<BindingAdapterItem> items = new ArrayList<>();
        items.add(new TextBean("哈哈哈哈"));
        items.add(new ImageBean());
        items.add(new Image2Bean());
        items.add(new Image2Bean());
        items.add(new TextBean("我又來啦"));
        items.add(new Image2Bean());
        items.add(new ImageBean());
        items.add(new TextBean("我還來"));
        items.add(new TextBean("就是不讓你看美女"));
        items.add(new Image2Bean());
        items.add(new ImageBean());
        items.add(new TextBean("哈哈你當不住我看見啦"));
        BindingAdapter adapter = new BindingAdapter();
        adapter.setItems(items);
        //這也是一個坑,經常忘了加LayoutManger導致東西Item無法顯示,RecyclerView把測量,布局的工作甩給了LayoutManager
        LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext());
        binding.rv.setLayoutManager(manager);
        binding.rv.setAdapter(adapter);
        adapter.notifyDataSetChanged();

就像平常使用RecyclerView一樣,用一個List包裝要顯示的數據,其中TextBean,ImageBean,Image2Bean是對應三種不同布局的實體類。那么這些實體類里邊一定要有一些信息能夠讓BindingAdapter識別他們的布局信息,最簡單的方法就是在這些實體重直接返回布局文件,把他們返回布局的共同方法命名為int getViewType()并創(chuàng)造一個新的iterface來封裝這個方法:

public interface BindingAdapterItem {
    int getViewType();
}

以后每一個Item只需要實現(xiàn)這個接口中的int getViewType()方法就能告訴Adapter自己的布局了。

例如TextItem的實現(xiàn)為:

public class TextBean extends BaseObservable implements BindingAdapterItem {
    @Override
    public int getViewType() {
        return R.layout.adapter_text;
    }

    public TextBean(String text) {
        this.text = text;
    }

    private String text;

    @Bindable
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
        notifyPropertyChanged(BR.text);
    }
}


繼承BaseObservalable是為了將數據與界面綁定,詳情請閱讀開頭的兩篇文章。
再看一下TextItem的layout的內容:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="item"
            type="com.example.m.bean.TextBean"/>
    </data>
    <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{item.text}"
            android:gravity="center"
            android:textSize="25sp"
            />
</layout>

剛剛講過ViewDataBing通過

boolean setVariable(int variableId, Object value)

方法來將數據綁定到界面上,其中int variableId指的是變量在BR類中的ID,

 <data>
        <variable
            name="item"
            type="com.example.m.bean.TextBean"/>
    </data>

中的name,而Object value對應其中的type,在

 android:text="@{item.text}"

中將TextItem中的text屬性綁定到對對應的控件上.

  <data>
        <variable
            name="item"
            type="com.example.m.bean.TextBean"/>
    </data>

好的下面去往通用的BindingAdapter去看看

public class BindingAdapter extends RecyclerView.Adapter<BindingAdapter.BindingHolder> {


    public List<BindingAdapterItem> getItems() {
        return items;
    }

    public void setItems(List<BindingAdapterItem> items) {
        this.items = items;
    }
    List<BindingAdapterItem> items = new ArrayList<>();
    
    /**
     * @return 返回的是adapter的view
     */
    @Override
    public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), viewType, parent, false);
        return new BindingHolder(binding);
    }
    /*
    * 數據綁定
    * */
    @Override
    public void onBindViewHolder(BindingHolder holder, int position) {
        holder.bindData(items.get(position));
    }
    @Override
    public int getItemCount() {
        return items.size();
    }
    @Override
    public int getItemViewType(int position) {
        return items.get(position).getViewType();
    }

    static class BindingHolder extends RecyclerView.ViewHolder {

        ViewDataBinding binding;
         /**
         * @param binding   可以看作是這個hodler代表的布局的馬甲,getRoot()方法會返回整個holder的最頂層的view
         * */
        public BindingHolder(ViewDataBinding binding) {
            //
            super(binding.getRoot());
            this.binding = binding;
        }

        public void bindData(BindingAdapterItem item) {
            binding.setVariable(BR.item,item);
        }

    }
}

這個類的基本要求是:

  • 能夠根據傳進來的對定的item判斷對應的布局,
  • 能夠自動的把傳進來的數據顯示到對應的布局上;

adpter獲取正確的布局很簡單,只需要重寫int getItemViewType(int position)方法,在里邊直接返回item里邊的layout就行了:

 @Override
    public int getItemViewType(int position) {
        return items.get(position).getViewType();
    }

現(xiàn)在先用ViewDataBinding來取代View,標準的VIewholder應該是通過layout的rootView來構造,我們可以通過ViewDataBinding.getRoot()來返回這個rootview

  ViewDataBinding binding;
         /**
         * @param binding   可以看作是這個hodler代表的布局的馬甲,getRoot()方法會返回整個holder的最頂層的view
         * */
        public BindingHolder(ViewDataBinding binding) {
            //
            super(binding.getRoot());
            this.binding = binding;
        }

綁定數據的時候只需要將實例化后的實體類對象傳入ViewDataBinding的對應的virable中就好了:

public void bindData(BindingAdapterItem item) {
            //
            binding.setVariable(BR.item,item);
        }

因為這里的int variableId是固定的BR.item所以每一個layout中variable的name屬性必須為item!
在Adapter的onCreateViewHolder(ViewGroup parent, int viewType)中改用獲取對應的ViewDataBing來初始化ViewHodler:

 @Override
    public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), viewType, parent, false);
        return new BindingHolder(binding);
    }

然后在onBindViewHolder(BindingHolder holder, int position)中調用就好了:

 @Override
    public void onBindViewHolder(BindingHolder holder, int position) {
        holder.bindData(items.get(position));
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容