寫在前面
我們的目標是 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 簡直上天
原始碼
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/hongyangAnd… (基於它封裝的)