Search code examples
javaandroidandroid-databinding

Invalidating caches and restarting doesn't fix the BR import bug...Databinding issue


Almost finished this app and running into compile time error with the data binding aspect in my Movie class I've extended BaseObserver and on trying to build project I can't import BR for the notifyPropertyChanged(BR.voteCount); on a setter. I can't see the issue but if I try compile and it were to get passed that it crashes on launch with the following stack trace.

stackTrace

I figured if it's a problem with the generated code then how do I tinker with that???

Really puzzled! Any help appreciated.

I've added dependencies can't see no issues there....

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    dataBinding {
        enabled = true
    }
    buildToolsVersion "29.0.0"
    defaultConfig {
        applicationId "com.example.tmdbclient"
        minSdkVersion 19
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    def lifecycle_version = "2.0.0"

    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx

    annotationProcessor 'com.android.databinding:compiler:2.3.0'

    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    implementation 'com.android.support:cardview-v7:29.0.0'
    implementation 'com.android.support:recyclerview-v7:29.0.0'
    implementation 'com.android.support:design:29.0.0'
    implementation 'com.github.bumptech.glide:glide:4.9.0'

}

Model

package com.example.tmdbclient.model;

import android.os.Parcel;
import android.os.Parcelable;
import android.widget.ImageView;


import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.databinding.BindingAdapter;
import androidx.databinding.BR;
import com.bumptech.glide.Glide;
import com.example.tmdbclient.R;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

import java.util.ArrayList;
import java.util.List;

public class Movie extends BaseObservable implements Parcelable
{

    @SerializedName("vote_count")
    @Expose
    private Integer voteCount;
    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("video")
    @Expose
    private Boolean video;
    @SerializedName("vote_average")
    @Expose
    private Double voteAverage;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("popularity")
    @Expose
    private Double popularity;
    @SerializedName("poster_path")
    @Expose
    private String posterPath;
    @BindingAdapter("posterPath")
    public void loadImage(ImageView imageView, String imageURL) {

        String imagePath = "https://image.tmdb.org/t/p/w500" + imageURL;

        Glide.with(imageView.getContext())
                .load(imagePath)
                .placeholder(R.drawable.loading)
                .into(imageView);



    }


    @SerializedName("original_language")
    @Expose
    private String originalLanguage;
    @SerializedName("original_title")
    @Expose
    private String originalTitle;
    @SerializedName("genre_ids")
    @Expose
    private List<Integer> genreIds = new ArrayList<Integer>();
    @SerializedName("backdrop_path")
    @Expose
    private String backdropPath;
    @SerializedName("adult")
    @Expose
    private Boolean adult;
    @SerializedName("overview")
    @Expose
    private String overview;
    @SerializedName("release_date")
    @Expose
    private String releaseDate;
    public final static Parcelable.Creator<Movie> CREATOR = new Creator<Movie>() {


        @SuppressWarnings({
                "unchecked"
        })
        public Movie createFromParcel(Parcel in) {
            return new Movie(in);
        }

        public Movie[] newArray(int size) {
            return (new Movie[size]);
        }

    }
            ;

    protected Movie(Parcel in) {
        this.voteCount = ((Integer) in.readValue((Integer.class.getClassLoader())));
        this.id = ((Integer) in.readValue((Integer.class.getClassLoader())));
        this.video = ((Boolean) in.readValue((Boolean.class.getClassLoader())));
        this.voteAverage = ((Double) in.readValue((Double.class.getClassLoader())));
        this.title = ((String) in.readValue((String.class.getClassLoader())));
        this.popularity = ((Double) in.readValue((Double.class.getClassLoader())));
        this.posterPath = ((String) in.readValue((String.class.getClassLoader())));
        this.originalLanguage = ((String) in.readValue((String.class.getClassLoader())));
        this.originalTitle = ((String) in.readValue((String.class.getClassLoader())));
        in.readList(this.genreIds, (java.lang.Integer.class.getClassLoader()));
        this.backdropPath = ((String) in.readValue((String.class.getClassLoader())));
        this.adult = ((Boolean) in.readValue((Boolean.class.getClassLoader())));
        this.overview = ((String) in.readValue((String.class.getClassLoader())));
        this.releaseDate = ((String) in.readValue((String.class.getClassLoader())));
    }

    public Movie() {
    }


    @Bindable
    public Integer getVoteCount() {
        return voteCount;
    }

    public void setVoteCount(Integer voteCount) {
        this.voteCount = voteCount;
        notifyPropertyChanged(BR.voteCount);
    }


    @Bindable
    public Integer getId() {
        return id;
    }

    public void setId(Integer id)
    {
        this.id = id;
        notifyPropertyChanged(com.example.tmdbclient.BR.id);


    }

    @Bindable
    public Boolean getVideo() {
        return video;
    }

    public void setVideo(Boolean video) {

        this.video = video;
        notifyPropertyChanged(BR.video);
    }

    @Bindable
    public Double getVoteAverage() {
        return voteAverage;
    }

    public void setVoteAverage(Double voteAverage) {

        this.voteAverage = voteAverage;
        notifyPropertyChanged(BR.voteAverage);
    }

    @Bindable
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {

        this.title = title;
        notifyPropertyChanged(BR.title);
    }

    @Bindable
    public Double getPopularity() {
        return popularity;
    }

    public void setPopularity(Double popularity) {

        this.popularity = popularity;
        notifyPropertyChanged(BR.popularity);
    }

    @Bindable
    public String getPosterPath() {
        return posterPath;
    }

    public void setPosterPath(String posterPath) {

        this.posterPath = posterPath;
        notifyPropertyChanged(BR.posterPath);
    }

    @Bindable
    public String getOriginalLanguage() {
        return originalLanguage;
    }

    public void setOriginalLanguage(String originalLanguage) {
        this.originalLanguage = originalLanguage;
        notifyPropertyChanged(BR.originalLanguage);
    }

    @Bindable
    public String getOriginalTitle() {
        return originalTitle;
    }

    public void setOriginalTitle(String originalTitle) {

        this.originalTitle = originalTitle;
        notifyPropertyChanged(BR.originalTitle);
    }

    @Bindable
    public List<Integer> getGenreIds() {
        return genreIds;
    }

    public void setGenreIds(List<Integer> genreIds) {

        this.genreIds = genreIds;
        notifyPropertyChanged(BR.genreIds);
    }

    @Bindable
    public String getBackdropPath() {
        return backdropPath;
    }

    public void setBackdropPath(String backdropPath) {

        this.backdropPath = backdropPath;
        notifyPropertyChanged(BR.backdropPath);
    }

    @Bindable
    public Boolean getAdult() {
        return adult;
    }

    public void setAdult(Boolean adult) {

        this.adult = adult;
        notifyPropertyChanged(BR.adult);
    }

    @Bindable
    public String getOverview() {
        return overview;
    }

    public void setOverview(String overview) {
        this.overview = overview;
        notifyPropertyChanged(BR.overview);
    }

    @Bindable
    public String getReleaseDate() {
        return releaseDate;
    }

    public void setReleaseDate(String releaseDate) {

        this.releaseDate = releaseDate;
        notifyPropertyChanged(BR.releaseDate);
    }


    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(voteCount);
        dest.writeValue(id);
        dest.writeValue(video);
        dest.writeValue(voteAverage);
        dest.writeValue(title);
        dest.writeValue(popularity);
        dest.writeValue(posterPath);
        dest.writeValue(originalLanguage);
        dest.writeValue(originalTitle);
        dest.writeList(genreIds);
        dest.writeValue(backdropPath);
        dest.writeValue(adult);
        dest.writeValue(overview);
        dest.writeValue(releaseDate);
    }

    public int describeContents() {
        return 0;
    }

}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"

    >
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout 
    android:id="@+id/swipe"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.MainActivity"
    android:layout_marginTop="15dp">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvMovies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:scrollbars="vertical"/>
</RelativeLayout>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</layout>

activity_movie

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="movie"
            type="com.example.tmdbclient.model.Movie" />

    </data>

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".view.MovieActivity">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"

            android:theme="@style/Widget.Design.AppBarLayout">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/ctMovie"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp"
                app:expandedTitleTextAppearance="@android:color/transparent"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">


                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">

                    <ImageView
                        android:id="@+id/ivMovieLarge"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:fitsSystemWindows="true"
                        app:layout_collapseMode="parallax"
                        bind:posterPath="@{movie.posterPath}" />
                </RelativeLayout>

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="?attr/colorPrimary"
                    app:layout_collapseMode="pin" />


            </com.google.android.material.appbar.CollapsingToolbarLayout>

        </com.google.android.material.appbar.AppBarLayout>


        <include
            android:id="@+id/secondary_layout"
            layout="@layout/content_movie"
            bind:secondaryMovie="@{movie}" />

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</layout>

content_movie

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="secondaryMovie"
            type="com.example.tmdbclient.model.Movie" />

    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context=".view.MovieActivity"
        tools:showIn="@layout/activity_movie">

        <LinearLayout
            android:id="@+id/add"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:showIn="@layout/activity_movie">

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <TextView
                        android:id="@+id/tvMovieTitle"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="3dp"
                        android:padding="16dp"
                        android:text="@{secondaryMovie.title}"
                        android:textSize="20sp"
                        app:layout_constraintLeft_creator="1"
                        app:layout_constraintLeft_toLeftOf="parent"
                        app:layout_constraintTop_creator="1"
                        app:layout_constraintTop_toTopOf="parent" />

                    <TextView
                        android:id="@+id/tvRating"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="3dp"
                        android:padding="16dp"
                        android:text="@{Double.toString(secondaryMovie.voteAverage)}"
                        android:textSize="16sp"
                        app:layout_constraintLeft_creator="1"
                        app:layout_constraintLeft_toLeftOf="parent"
                        app:layout_constraintTop_creator="1"
                        app:layout_constraintTop_toBottomOf="@id/tvMovieTitle"

                        />


                    <TextView
                        android:id="@+id/tvSynopsis"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="3dp"
                        android:padding="16dp"
                        android:text="@{secondaryMovie.overview}"
                        android:textSize="16sp"
                        app:layout_constraintLeft_creator="1"
                        app:layout_constraintLeft_toLeftOf="parent"
                        app:layout_constraintTop_creator="1"
                        app:layout_constraintTop_toBottomOf="@id/tvRating"

                        />


                    <TextView
                        android:id="@+id/tvRelease"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="3dp"
                        android:padding="16dp"
                        android:text="@{secondaryMovie.releaseDate}"
                        android:textSize="16sp"
                        app:layout_constraintLeft_creator="1"
                        app:layout_constraintLeft_toLeftOf="parent"
                        app:layout_constraintTop_creator="1"
                        app:layout_constraintTop_toBottomOf="@id/tvSynopsis"

                        />

                </androidx.constraintlayout.widget.ConstraintLayout>


            </ScrollView>
        </LinearLayout>
    </RelativeLayout>

</layout>

movie_list_item

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="movie"
            type="com.example.tmdbclient.model.Movie" />

    </data>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <androidx.cardview.widget.CardView
            android:id="@+id/cvMovie"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:elevation="3dp"
            app:cardCornerRadius="3dp">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ImageView
                    android:id="@+id/ivMovie"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:background="?attr/selectableItemBackgroundBorderless"
                    android:scaleType="fitXY"
                    bind:posterPath="@{movie.posterPath}" />


                <TextView
                    android:id="@+id/tvTitle"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/ivMovie"
                    android:paddingLeft="10dp"
                    android:paddingTop="10dp"
                    android:paddingRight="10dp"
                    android:text="@{movie.title}"
                    android:textColor="@color/colorPrimary"
                    android:textSize="15sp" />


                <TextView
                    android:id="@+id/tvRating"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/tvTitle"
                    android:paddingLeft="10dp"
                    android:paddingTop="10dp"
                    android:paddingRight="10dp"
                    android:text="@{Double.toString(movie.voteAverage)}"
                    android:textColor="@color/colorPrimary"
                    android:textSize="15sp" />

            </RelativeLayout>
        </androidx.cardview.widget.CardView>
    </LinearLayout>

</layout>

Solution

  • First thing you should do is

    Change these lines

    implementation 'com.android.support:cardview-v7:29.0.0'
    implementation 'com.android.support:recyclerview-v7:29.0.0'
    implementation 'com.android.support:design:29.0.0'
    

    to

    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation 'androidx.design:design:1.0.0'
    

    Problem is with your loadImage method of Movie class. Define it static and it should work.