使用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);
复制代码

参考文章

相关文章
相关标签/搜索