I would like to create a gridview of movie posters images with using bindings.
My viewmodel looks like that:
public class PopularMoviesViewModel extends BaseObservable {
Movie movie;
Context context;
MovieServiceComponent movieServiceComponent = DaggerMovieServiceComponent.builder()
.contextModule(new ContextModule(context))
.build();
Picasso getPicasso = movieServiceComponent.getPicasso();
public PopularMoviesViewModel(Movie movie, Context context) {
this.movie = movie;
this.context = context;
}
@Bindable
public String getImageUrl(){
return movie.posterPath();
}
@Bindable
public String getTitle(){
return movie.originalTitle();
}
@BindingAdapter({"imageUrl"})
public void setImageUrl(ImageView view, String poserPath){
getPicasso.with(view.getContext()).load("http://image.tmdb.org/t/p/w185"+ poserPath).into(view);
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data class="PopularMoviesBinding">
<variable
name="pmvm"
type="com.hartyandi.oviesm.modelviews.PopularMoviesViewModel"></variable>
</data>
<LinearLayout
android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:paddingBottom="0dp"
android:paddingTop="5dp"
android:paddingRight="2.5dp"
android:paddingLeft="5dp"
android:orientation="vertical">
<ImageView
app:imageUrl="@{pmvm.imageUrl}"
android:id="@+id/popular_movies_grid_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="0dp"
android:adjustViewBounds="true"
android:elevation="20dp">
</ImageView>
<TextView
android:id="@+id/popular_movies_grid_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{pmvm.title}"
android:textColor="#000000"
android:textSize="12sp"
android:background="#FFFFFF"
>
</TextView>
</LinearLayout>
</layout>
Adapter:
public class PopularMoviesAdapter extends RecyclerView.Adapter<PopularMoviesAdapter.BindingHolder> {
private List<Movie> movies;
private Context context;
public PopularMoviesAdapter(List<Movie> movies, Context context) {
this.movies = movies;
this.context = context;
}
public void add(Movie movie){
movies.add(movie);
}
@Override
public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
PopularMoviesBinding popularMoviesBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.popular_movies_gridview_row, parent,false);
return new BindingHolder(popularMoviesBinding);
}
@Override
public void onBindViewHolder(PopularMoviesAdapter.BindingHolder holder, int position) {
PopularMoviesBinding popularMoviesBinding = holder.popularMoviesBinding;
popularMoviesBinding.setPmvm(new PopularMoviesViewModel(movies.get(position), context));
}
@Override
public int getItemCount() {
return movies.size();
}
public class BindingHolder extends RecyclerView.ViewHolder{
private PopularMoviesBinding popularMoviesBinding;
public BindingHolder(PopularMoviesBinding popularMoviesBinding) {
super(popularMoviesBinding.getRoot());
this.popularMoviesBinding = popularMoviesBinding;
}
}
}
I get the following error:
java.lang.IllegalStateException: Required DataBindingComponent is null in class PopularMoviesBinding.A BindingAdapter in modelviews.PopularMoviesViewModel is not static and requires an object to use, retrieved from the DataBindingComponent.
I tried to change my implementation just like this stackoverflow post suggest and I got the same error message.
I also used the following code as example.
Could someone explain what the problem with the code, and how to solve it?
You probably didn't intend to use an instance method for the BindingAdapter
.
If you do, you must provide a DataBindingComponent so that the generated Binding class knows which instance to use.
You have two options -- provide a DataBindingComponent
or just pass the required context as an attribute to a static binding adapter method. The second is a bit easier to understand, so I'll start with that:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data class="PopularMoviesBinding">
<variable name="pmvm"
type="com.hartyandi.oviesm.modelviews.PopularMoviesViewModel"/>
<variable name="picasso" type="com.whatever.Picasso"/>
</data>
<!-- ... -->
<ImageView
app:imageUrl="@{pmvm.imageUrl}"
app:picasso="@{picasso}"
... />
</ImageView>
</layout>
Then in your BindingAdapter:
@BindingAdapter({"imageUrl", "picasso"})
public static void setImageUrl(ImageView view, String poserPath, Picasso picasso){
picasso.with(view.getContext()).load("http://image.tmdb.org/t/p/w185"+ poserPath).into(view);
}
Note that setImageUrl is now static
.
Alternatively, since your the Picasso instance is also on the ViewModel, you can just pass the instance by adding a getter for the picasso:
<ImageView
app:imageUrl="@{pmvm.imageUrl}"
app:picasso="@{pmvm.picasso}"
... />
and the method in your ViewModel:
public Picasso getPicasso() { return this.getPicasso; }
The other way means that you implement a DataBindingComponent
. When you create an instance BindingAdapter method, the generated interface will have a getter for your class. You'll need to create a class to implement that interface:
public class MyDataBindingComponent implements DataBindingComponent {
public PopularMoviesViewModel getPopularMoviesViewModel() {
return whateverIDoToCreateOrGetThisBindingAdapterInstance();
}
}
Then you pass the instance when you inflate or bind:
PopularMoviesBinding popularMoviesBinding =
DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.popular_movies_gridview_row, parent,false,
new MyDataBindingComponent());
just make the setImageUrl() method static to be like this code
@BindingAdapter({"imageUrl"})
public void setImageUrl(ImageView view, String poserPath){
getPicasso.with(view.getContext()).load("http://image.tmdb.org/t/p/w185"+
poserPath).into(view);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With