No ViewHolder!!! 一個非官方的純java版 databinding(拒絕xml配置).

寫在前面

我們的目標是 No ViewHolder and No Adapter.

官方的databinding的確十分厲害,各種xml綁定,然後自動生成一波文件,各種吊的飛起,不過容易讓人抓不住重點。爲了加深理解,我寫了這個純java版databindng, 不需要xml各種配置android:text="@{...}",同時進一步加了綁定Adapter

時間倉促,只粗略的實現了小部分功能。基於註解的性能也有待優化,但它已經極大地提升了我的開發效率。覺得它不錯的話,可以一起維護這個項目,向No ViewHolder的目標邁進~

預覽

常規的電商首頁

所需代碼量

實現這樣一個帶Header, 帶上拉加載的列表需要多少代碼呢?
- 兩個無聊的 javabean
- 一個輪播控件
- 一個Activity(真的不含 Adapter 啊)
- 然後沒有然後了。。。

特性

  • data -> view的單向綁定
  • 支持常用控件的綁定,同時增加了官方沒有的Adapter綁定。支持Header上拉加載
  • 代碼極其簡潔, 無需實例化View, 也沒有Adapter, 連ViewHoler 也沒有。。。
  • 支持綁定行爲的自定義
  • 配合 Rxjava + Lambda 簡直上天

源碼

https://github.com/fashare2015/NoViewHolder

gralde 依賴

// 1. Add it in your root build.gradle at the end of repositories:
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

// 2. Add the dependency in your app/build.gradle
dependencies {
        compile 'com.github.fashare2015:NoViewHolder:1.0.1'
}

綁定 Data 和 View

這一塊和官方差不多,只是xml配置換成了java註解配置。

綁定單個 View

首先,你手頭有一個javabean,就是你在圖中看到的妹子列表Item如:

public class MeiZhi {
    @BindImageView(id=R.id.iv_image, placeHolder = R.mipmap.ic_launcher)
    public String url;  // 把 url 綁定在 ImageView 上
    @BindTextView(id=R.id.tv_title)
    public String desc; // 把 desc 綁定在 TextView 上
}

基本等同於官方的android:text="@{meizhi.desc}",用過databinding的話應該秒懂的。。。

綁定列表

當然,服務端返回的肯定是個妹子的列表,你手頭還會有一個HomeInfo的東東。

public class HomeInfo {
    // 妹子列表區
    @BindRecyclerView(id = R.id.rv_meizhi, layout = R.layout.item_meizhi)
    private List<MeiZhi> results = new ArrayList<>();   // 把 List 綁定在 RecyclerView 上

    // banner
    @BindViewPager(id = R.id.vp_banner, layout = R.layout.item_banner)
    private List<MeiZhi> bannerInfo;    // 把 List 綁定在 ViewPager 上
}

這部分是官方沒有的,相應的還提供了 @BindListView

綁定 header

像上面的配置,banner和妹子列表是分開的,不會一起滑動的。因此,提供了向RecyclerView中添加Header的註解——@BindRvHeader.
讓我們把banner加進RecyclerView

public class HomeInfo {
    // 妹子列表區
    @BindRecyclerView(id = R.id.rv_meizhi, layout = R.layout.item_meizhi)
    private List<MeiZhi> results = new ArrayList<>();   // 把 List 綁定在 RecyclerView 上

    // banner
    @BindRvHeader(id = R.id.rv_meizhi, layout = R.layout.layout_banner, itemType = 0) // 增加這一行 !!!
    @BindViewPager(id = R.id.vp_banner, layout = R.layout.item_banner)
    private List<MeiZhi> bannerInfo;    // 把 List 綁定在 ViewPager 上
}

綁定點擊事件

提供了@BindItemClick@BindClick

public class MainActivity extends AppCompatActivity {
    ...
    @BindItemClick(id = R.id.vp_banner)
    NoOnItemClickListener<MeiZhi> clickBanner = (view, data, pos) -> toast("click Banner: " + pos + ", "+ data.toString());

    @BindItemClick(id = R.id.rv_meizhi)
    NoOnItemClickListener<MeiZhi> clickMeiZhi = (view, data, pos) -> toast("click MeiZhi: " + pos + ", "+ data.toString());
}

更新 UI

前面只是一系列綁定關係的配置,還需要一個接口觸發他們:
- 初始化:根據 R.id.XXX 初始化相應的 View 和 Adapter,爲後續更新UI做準備

mNoViewHolder = new NoViewHolder.Builder(this)
                .initView(new HomeInfo()) // 一定要提供`註解信息`的類,否則無法初始化。
                .build();
  • 更新UI: mNoViewHolder.notifyDataSetChanged(homeInfo);
    自動根據 homeInfo 裏提供的註解信息,找到相應的控件,並把數據刷新上去。
// 在請求的 onSuccess() 中刷新界面,本例使用了 Rxjava 和 lambda
homeInfoObservable.subscribe(homeInfo -> {
        mHomeInfo.getResults().addAll(homeInfo.getResults());           // 更新 妹子列表 info
        if(homeInfo.getResults().size() >= 6)
            mHomeInfo.setBannerInfo(homeInfo.getResults().subList(0, 6));   // 更新 bannerInfo

        mNoViewHolder.notifyDataSetChanged(mHomeInfo);  // mHomeInfo 發生變化, 通知 UI 及時刷新
}

全局配置——自定義行爲

當你需要自定義的時候 (比如替換圖片加載庫,默認Glide)。可以這樣:
如下,即把@BindTextView的行爲override掉了。

    static NoViewHolder.Options mDataOptions = new NoViewHolder.DataOptions()
            .setBehaviors(new BindTextView.Behavior() {
                @Override
                public void onBind(TextView targetView, BindTextView annotation, Object value) {
                    targetView.setText("fashare 到此一遊" + value);
                }
            });

    static {
        NoViewHolder.setDataOptions(mDataOptions);
    }

總結

水平有限,實現的比較粗糙。但我覺得這個思路還行,用起來簡潔性也絲毫不比官方的差。覺得它不錯的話,可以一起維護這個項目,向No ViewHolder的目標邁進~

一些類似實現

https://github.com/Kelin-Hong/MVVMLight

https://github.com/evant/binding-collection-adapter

感謝

https://github.com/hongyangAndroid/baseAdapter (基於它封裝的)

https://github.com/mcxtzhang/all-base-adapter

完全掌握Android Data Binding

[譯]關於 Android Adapter,你的實現方式可能一直都有問題

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