Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setup a @BindingAdapter with Picasso?

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?

like image 791
GaborH Avatar asked Jan 24 '17 20:01

GaborH


2 Answers

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());
like image 122
George Mount Avatar answered Nov 12 '22 23:11

George Mount


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);

}
like image 37
Mohamed Kamel Avatar answered Nov 13 '22 00:11

Mohamed Kamel