使用Android DataBinding BindingAdapter和Dagger 2

使用Android 數據綁定庫實現綁定適配器的典型方法是使用@BindingAdapter註釋建立靜態方法,例如:html

@BindingAdapter("android:imageUrl")
public static void loadImage(ImageView view, String url) {
    Picasso.get().load(url).into(view);
}

複製代碼

這已在網上普遍使用和討論並適用於不少個例(若是你熟悉DataBinding的話)。android

可是,若是你想你的適配器具備很好耦合度,或者您不想在全局範圍內定義它,該怎麼辦?bash

BindingAdapter並不必定要是靜態的......app

建立非靜態綁定適配器

不使用Dagger2也能實現

官方文檔徹底沒有DataBinding的這種功能,可是在Stack Overflow上有一些例子。 我舉個例子說明一下。 我建立了三個綁定適配器的接口類:ide

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一下,咱們發現DataBindingComponent類是會自動生成的(在build / generated / source / apt / dev下)。 此接口包含爲每一個單獨的適配器定義的getter:函數

public interface DataBindingComponent {
    ViewBindingInterface getViewBindingInterface();
    ViewBindingInterface getTextViewBindingInterface();
    ImageViewBindingInterface getImageViewBindingInterface();
}
複製代碼

而後咱們建立一個基類去實現它佈局

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就能夠了ui

public class MyApplication extends Application {
    public void onCreate() {
        super.onCreate();
        DataBindingUtil.setDefaultComponent(new MyOwnDefaultDataBindingComponent());
    }
}
複製代碼

優化了一下,讓本身的代碼看起來更舒服,更低耦合。是否是也很簡單呢?this

使用Dagger2注入

讓咱們建立一個相似上面例子的簡單適配器:

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如今不是每次都建立一個新的Picasso實例,而是做爲一個依賴者傳遞給構造函數。特別是對於Picasso來講,若是你想使用構建器來建立一個自定義實例而且避免使用Picasso的多個實例,這可能會頗有用。 以這種方式建立BindingAdapter時,DataBinding跟上面同樣也會生成DataBindingComponent接口

public interface DataBindingComponent {
    ImageBindingAdapter getImageBindingAdapter();
}

複製代碼

縱觀DataBindingUtil 文檔 ,咱們能夠看到有不少的利用方法DataBindingComponent,好比setDefaultComponentinflatesetContentView(之後會更多)。

使用適配器的一種方法是建立一個具體的實現DataBindingComponent,這能夠手動完成,也可使用Dagger 2來利用圖形來提供任何外部依賴。

使用Dagger構建DataBindingComponent

應該能夠建立組件或子組件,在此示例中,我選擇使用組件,由於沒必要將整個圖形暴露給綁定適配器。

組件須要一個範圍,因此我@DataBinding建立了一個Scope做用域。

這是提供如下內容的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會自動實現了全部的方法DataBindingComponent。如下是自動生成的內容片斷:

public final class DaggerBindingComponent implements BindingComponent {

    private Provider<ImageBindingAdapter> provideImageBindingAdapterProvider;

    @Override
    public ImageBindingAdapter getImageBindingAdapter() {
        return provideImageBindingAdapterProvider.get();
    }

    ....
}

複製代碼

使用Component

使用新組件的最簡單方法是在Application類中建立它,特別是若是在Dagger 2.10+中使用Android注入,由於您再也不須要將主要組件在·Acitivity·中inject。它如今是一個標準的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);
    }
}

複製代碼

這固然在全局範圍內有效啦!!這個組件也能夠與特定佈局一塊兒使用!!!:

Activity中:

DataBindingUtil.setContentView(this, R.layout.activity_layout, bindingComponent);
複製代碼

Fragment中:

DataBindingUtil.inflate(inflater, R.layout.fragment_layout, container, false, bindingComponent);
複製代碼

參考文章

相關文章
相關標籤/搜索