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

梁山boy發表於2017-03-15

寫在前面

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

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

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

預覽

常規的電商首頁

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

所需程式碼量

實現這樣一個帶Header, 帶上拉載入的列表需要多少程式碼呢?

  • 兩個無聊的 javabean
  • 一個輪播控制元件
  • 一個Activity(真的不含 Adapter 啊)
  • 然後沒有然後了。。。

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

特性

  • data -> view的單向繫結
  • 支援常用控制元件的繫結,同時增加了官方沒有的Adapter繫結。支援Header上拉載入
  • 程式碼極其簡潔, 無需例項化View, 也沒有Adapter, 連ViewHoler 也沒有。。。
  • 支援繫結行為的自定義
  • 配合 Rxjava + Lambda 簡直上天

原始碼

github.com/fashare2015…

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的目標邁進~

一些類似實現

github.com/Kelin-Hong/…

github.com/evant/bindi…

感謝

github.com/hongyangAnd… (基於它封裝的)

github.com/mcxtzhang/a…

完全掌握Android Data Binding

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

相關文章