使用Android 數(shù)據(jù)綁定庫實現(xiàn)綁定適配器的典型方法是使用@BindingAdapter注釋創(chuàng)建靜態(tài)方法,例如:
@BindingAdapter("android:imageUrl")
public static void loadImage(ImageView view, String url) {
Picasso.get().load(url).into(view);
}
這已在網(wǎng)上廣泛使用和討論,并適用于很多個例(如果你熟悉DataBinding的話)。
但是,如果你想你的適配器具有很好耦合度,或者您不想在全局范圍內(nèi)定義它,該怎么辦?
BindingAdapter并不一定要是靜態(tài)的......
創(chuàng)建非靜態(tài)綁定適配器
不使用Dagger2也能實現(xiàn)
官方文檔完全沒有DataBinding的這種功能,但是在Stack Overflow上有一些例子。
我舉個例子說明一下。
我創(chuàng)建了三個綁定適配器的接口類:
public interface ImageViewBindingInterface {
@BindingAdapter({"bind:imageUrl", "bind:error"})
public void loadImage(ImageView view, String url, Drawable error);
}
public interface TextViewBindingInterface {
@BindingAdapter({"bind:font"})
void setFont(TextView textView, String fontName);
}
public interface ViewBindingInterface {
@BindingAdapter("android:paddingLeft")
public void setPaddingLeft(View view, int padding);
@BindingAdapter("android:onViewAttachedToWindow")
public void setListener(View view, ViewBindingAdapter.OnViewAttachedToWindow attached);
}
build一下,我們發(fā)現(xiàn)DataBindingComponent類是會自動生成的(在build / generated / source / apt / dev下)。
此接口包含為每個單獨的適配器定義的getter:
public interface DataBindingComponent {
ViewBindingInterface getViewBindingInterface();
ViewBindingInterface getTextViewBindingInterface();
ImageViewBindingInterface getImageViewBindingInterface();
}
然后我們創(chuàng)建一個基類去實現(xiàn)它
public class BaseImageViewBinding implements ImageViewBindingInterface{
@Override
public void loadImage(ImageView view, String url, Drawable error) {
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
}
public class BaseTextViewBinding implements TextViewBindingInterface {
@Override
public void setFont(TextView textView, String fontName) {
textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}
}
public class BaseViewBinding implements ViewBindingInterface {
@Override
public void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
@Override
public void setListener(View view, ViewBindingAdapter.OnViewAttachedToWindow attached) {
}
}
最后再設置你自己的DatabindingComponent:
public class MyOwnDefaultDataBindingComponent implements android.databinding.DataBindingComponent {
@Override
public ViewBindingInterface getViewBindingInterface() {
return new BaseViewBinding();
}
@Override
public TextViewBindingInterface getTextViewBindingInterface() {
return new BaseTextViewBinding();
}
@Override
public ImageViewBindingInterface getImageViewBindingInterface() {
return new BaseImageViewBinding();
}
}
最后在Application中設置默認的DataBindingComponent就可以了
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
DataBindingUtil.setDefaultComponent(new MyOwnDefaultDataBindingComponent());
}
}
優(yōu)化了一下,讓自己的代碼看起來更舒服,更低耦合。是不是也很簡單呢?
使用Dagger2注入
讓我們創(chuàng)建一個類似上面例子的簡單適配器:
public class ImageBindingAdapter {
private final Picasso picasso;
public ImageBindingAdapter(Picasso picasso) {
this.picasso = picasso;
}
@BindingAdapter("android:imageUrl")
public void loadImage(ImageView view, String url) {
picasso.load(url).fit().into(view);
}
}
Picasso現(xiàn)在不是每次都創(chuàng)建一個新的Picasso實例,而是作為一個依賴者傳遞給構造函數(shù)。特別是對于Picasso來說,如果你想使用構建器來創(chuàng)建一個自定義實例并且避免使用Picasso的多個實例,這可能會很有用。
以這種方式創(chuàng)建BindingAdapter時,DataBinding跟上面一樣也會生成DataBindingComponent接口
public interface DataBindingComponent {
ImageBindingAdapter getImageBindingAdapter();
}
縱觀DataBindingUtil 文檔 ,我們可以看到有很多的利用方法DataBindingComponent,比如setDefaultComponent,inflate和setContentView(以后會更多)。
使用適配器的一種方法是創(chuàng)建一個具體的實現(xiàn)DataBindingComponent,這可以手動完成,也可以使用Dagger 2來利用圖形來提供任何外部依賴。
使用Dagger構建DataBindingComponent
應該可以創(chuàng)建組件或子組件,在此示例中,我選擇使用組件,因為不必將整個圖形暴露給綁定適配器。
組件需要一個范圍,所以我@DataBinding創(chuàng)建了一個Scope作用域。
這是提供以下內(nèi)容的Module ImageBindingAdapter:
@Module
public class BindingModule {
@Provides @DataBinding
ImageBindingAdapter provideImageBindingAdapter(Picasso picasso) {
return new ImageBindingAdapter(picasso);
}
}
這是Component:
@DataBinding
@Component(dependencies = AppComponent.class, modules = BindingModule.class)
public interface BindingComponent extends DataBindingComponent {}
為了滿足Picasso的依賴性,BindingModule也必須由AppComponent(如果使用子組件則不需要此步驟)所引用:
@Singleton
@Component(modules = {AppModule.class, BindingModule.class})
public interface AppComponent {
private final Application application;
public AppModule(Application application) {
this.application = application;
}
Picasso picasso();
}
Build一下,Dagger會自動實現(xiàn)了所有的方法DataBindingComponent。以下是自動生成的內(nèi)容片段:
public final class DaggerBindingComponent implements BindingComponent {
private Provider<ImageBindingAdapter> provideImageBindingAdapterProvider;
@Override
public ImageBindingAdapter getImageBindingAdapter() {
return provideImageBindingAdapterProvider.get();
}
....
}
使用Component
使用新組件的最簡單方法是在Application類中創(chuàng)建它,特別是如果在Dagger 2.10+中使用Android注入,因為您不再需要將主要組件在·Acitivity·中inject。它現(xiàn)在是一個標準的Dagger組件,所以它只需要以正常的方式構建然后傳遞給它DataBindingUtil.setDefaultComponent(para)。
這是一個示例Application:
public class MyApplication extends Application {
@Override public void onCreate() {
super.onCreate();
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this))
.build();
appComponent.inject(this);
BindingComponent bindingComponent = DaggerBindingComponent.builder()
.appComponent(appComponent)
.build();
DataBindingUtil.setDefaultComponent(bindingComponent);
}
}
這當然在全局范圍內(nèi)有效啦!!這個組件也可以與特定布局一起使用?。。。?/p>
在Activity中:
DataBindingUtil.setContentView(this, R.layout.activity_layout, bindingComponent);
Fragment中:
DataBindingUtil.inflate(inflater, R.layout.fragment_layout, container, false, bindingComponent);
參考文章: