使用data binding和Picasso加载图片
英文原文:Loading images with data binding and Picasso
你在尝试使用Android data binding library吗?是否不知道如何加载图片到ImageViews?这里是如何显示图片的两个例子。
最近我创建了一个 MVVM 的app,它是作为Archi的一部分发布。Archi演示了安卓上的不同架构模式。这个app需要从GitHub API 下载profile图片并通过data binding把它们显示在一个ImageView上。本文我将大致描绘下实现它的两种方法。
下面的例子中使用的是Square的 Picasso 库来加载图片,但是你可以根据相同的方法使用其它图片加载库。
方法 1
使用 @BindingAdapter
这个方法使用BindingAdapter注解来创建一个自定义的xml属性。当这个属性以正确的类型设置到布局文件中时,ata binding 框架会触发被注解的方法。我把这个自定义的属性命名为imageUrl而参数类型为String。记住注解方法必须是静态的。
public class ProfileViewModel {
public String getImageUrl() {
// The URL will usually come from a model (i.e Profile)
return "http://cdn.meme.am/instances/60677654.jpg";
}
@BindingAdapter({"bind:imageUrl"})
public static void loadImage(ImageView view, String imageUrl) {
Picasso.with(view.getContext())
.load(imageUrl)
.placeholder(R.drawable.placeholder)
.into(view);
}
}
view model准备好之后,你可以创建你的布局文件并添加新的imageUrl属性到ImageView中。自定义属性需要使用app命名空间而不是android。
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<data>
<variable
name="viewModel"
type="uk.ivanc.imagedatabinding.ProfileViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
app:imageUrl="@{viewModel.imageUrl}" />
</RelativeLayout>
</layout>
最后一步像普通的data binding布局那样处理。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProfileActivityBinding binding =
DataBindingUtil.setContentView(this, R.layout.profile_activity);
binding.setViewModel(new ProfileViewModel(this));
}
方法2
ObservableField 与自定义 Picasso Target
第二种方法需要更多的代码不过跟第一种一样有效。这里的思路是使用一个类型为Drawablet的ObservableField与一个自定义Picasso Target。ObservableField可以包含任意类型的对象,在值发生改变的时候自动刷新布局,这里是一个Drawable对象。
这里的关键在于创建了一个接受了ObservableField与更新其值的句柄的自定义Picasso target。
public class ProfileViewModel {
// The URL will usually come from a model (i.e Profile)
static final String IMAGE_URL = "http://cdn.meme.am/instances/60677654.jpg";
public ObservableField<Drawable> profileImage;
private BindableFieldTarget bindableFieldTarget;
public ProfileViewModel(Context context) {
profileImage = new ObservableField<>();
// Picasso keeps a weak reference to the target so it needs to be stored in a field
bindableFieldTarget = new BindableFieldTarget(profileImage, context.getResources());
Picasso.with(context)
.load(IMAGE_URL)
.placeholder(R.drawable.placeholder)
.into(bindableFieldTarget);
}
public class BindableFieldTarget implements Target {
private ObservableField<Drawable> observableField;
private Resources resources;
public BindableFieldTarget(ObservableField<Drawable> observableField, Resources resources) {
this.observableField = observableField;
this.resources = resources;
}
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
observableField.set(new BitmapDrawable(resources, bitmap));
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
observableField.set(errorDrawable);
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
observableField.set(placeHolderDrawable);
}
}
}
BindableFieldTarged类需要只被写一次并且能在不同的项目中复用。
在布局文件中我们需要设置ImageView的src属性,让它指向ObservableField。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="uk.ivanc.imagedatabinding.ProfileViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@{viewModel.profileImage}"/>
</RelativeLayout>
</layout>
最后,记得按照前面的做法再进行一次绑定。参照第一个例子中的ProfileActivity.java。
两种方法都可以很好的工作但是我推荐使用第一种。它需要更少的代码而且可读性也更强。
如果你喜欢本文,点击推荐按钮!