使用Android 数据绑定库实现绑定适配器的典型方法是使用@BindingAdapter
注释创建静态方法,例如:
@BindingAdapter("android:imageUrl")
public static void loadImage(ImageView view, String url) {
Picasso.get().load(url).into(view);
}
这已在网上广泛使用和讨论,并适用于很多个例(如果你熟悉DataBinding的话)。
但是,如果你想你的适配器具有很好耦合度,或者您不想在全局范围内定义它,该怎么办?
BindingAdapter
并不一定要是静态的......
创建非静态绑定适配器
不使用Dagger2也能实现
官方文档完全没有DataBinding的这种功能,但是在Stack Overflow上有一些例子。
我举个例子说明一下。
我创建了三个绑定适配器的接口类:
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
就可以了
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
DataBindingUtil.setDefaultComponent(new MyOwnDefaultDataBindingComponent());
}
}
优化了一下,让自己的代码看起来更舒服,更低耦合。是不是也很简单呢?
使用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
,比如setDefaultComponent
,inflate
和setContentView
(以后会更多)。
使用适配器的一种方法是创建一个具体的实现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);
参考文章:
网友评论