Data Binding Component詳解
上一篇從零開始的Android新專案8 - Data Binding高階篇中,我們提到了使用Component來進行注入,以方便進行測試的功能,有一些朋友說寫的不夠清楚,還有些疑惑,所以本篇就來詳細說說Component。
作為例子,我們的實現目標是使用Data Binding Component,讓應用全域性的TextView的文字都能隨時變成test,還能進行全域性換膚。
DataBindingComponent介面
在build/intermediates/classes
下面,可以找到DataBindingComponent
類,包名為android.databinding
,全域性只會有一個該類——此介面在編譯時生成,包含了所有用到的例項BindingAdapters的getter方法。
當一個BindingAdapter是一個例項方法(instance method),一個實現該方法的類的例項必須被例項化。這個生成的介面會包含每個宣告BindingAdapter的類/介面的get方法。命名衝突會簡單地加一個數字字首到get方法前來解決。
如果使用Dagger 2,開發者可以繼承這個介面,並把繼承的介面註解為Component。
第一個介面全域性起作用,後兩個介面僅對該語句inflate的佈局起作用。
建立Component
宣告抽象adapter
如果不需要實現多個Component,可以直接跳過這一步。
我們宣告一個抽象的adapter,在其中寫上抽象方法來設定我們想要做data binding的屬性,這裡我們直接幹掉了TextView的android名稱空間下的text和textColor兩個屬性。
這裡的@BindingAdapter
註解會讓data binding在component中生成我們這個adapter的get方法(必須是非靜態的)。
public abstract class MyBindingAdapter {
@BindingAdapter("android:text")
public abstract void setText(TextView view, String value);
@BindingAdapter("android:textColor")
public abstract void setTextColor (TextView view, int value);
}
實現adapter
我們繼承MyBindingAdapter
分別實現兩個adapter:
ProductionBindingAdapter.java
:
public class ProductionBindingAdapter extends MyBindingAdapter {
@Override
public void setText(TextView view, String value) {
TextViewBindingAdapter.setText(view, value);
}
@Override
public void setTextColor(TextView view, int value) {
view.setTextColor(value);
}
}
TestBindingAdapter.java:
public class TestBindingAdapter extends MyBindingAdapter {
@Override
public void setText(TextView view, String value) {
view.setText(value + " test");
}
@Override
public void setTextColor(TextView view, int value) {
if (value == view.getContext()
.getResources()
.getColor(R.color.textColorDay)) {
view.setTextColor(view.getContext()
.getResources()
.getColor(R.color.textColorNight));
}
}
}
前者使用的是原來的設定,後者則分別給text加上了” test”字尾,並做了color的轉換,實現了字型顏色的“換膚”功能。
實現component
在寫了上面的程式碼後,再看看DataBindingComponent
,會發現裡面多了一個介面方法,遂實現之:
生產環境Component:
public class ProductionComponent implements DataBindingComponent {
private MyBindingAdapter mAdapter = new ProductionBindingAdapter();
@Override
public MyBindingAdapter getMyBindingAdapter() {
return mAdapter;
}
}
測試環境Component:
public class TestComponent implements DataBindingComponent {
private MyBindingAdapter mAdapter = new TestBindingAdapter();
@Override
public MyBindingAdapter getMyBindingAdapter() {
return mAdapter;
}
}
使用
layout
原先的text和textColor屬性並沒有通過data binding設定,我們要給它們套上@{}
:
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:onClick="@{presenter.onClickSimpleDemo}"
android:text="@{@string/demo_simple}"
android:textColor="@{@color/textColorDay}"/>
注入component
注入Component很簡單,我們做全域性的注入只需要呼叫:
if (DemoApplication.isTest) {
DataBindingUtil.setDefaultComponent(new ProductionComponent());
} else {
DataBindingUtil.setDefaultComponent(new TestComponent());
}
重新建立activity
由於點選事件在MainActivity
建立後才觸發,所以這個activity上並不會起作用,我們需要重新建立它:
public void onClickInjectDemo(View view) {
if (DemoApplication.isTest) {
DataBindingUtil.setDefaultComponent(new ProductionComponent());
} else {
DataBindingUtil.setDefaultComponent(new TestComponent());
}
DemoApplication.isTest = !DemoApplication.isTest;
recreate();
}
設定後recreate()
即可。可以看demo工程的效果,點選最後的按鈕後,字型顏色發生變化,textview的text後面都加上了test字串。
靜態adapter方法
那麼靜態的BindingAdapter方法怎麼去和Component做關聯呢?很簡單,只需要作為方法的第一個引數就可以了:
@BindingAdapter("android:src")
public static void loadImage(TestComponent component,
ImageView view, String url) {
/// ...
}
結
本篇我們實踐了Data Binding中比較高階的特性:Component。
其使用場景很多,如:
- 換膚
- 打點
- 替換原生屬性
- 等等
歡迎大家發揮自己的想象力,補充更多的使用場景。