Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AndroidX incompatible with DataBinding Android

Ok, I've been tasked with migrating a project to AndroidX to reduce the clutter of the support libs in our project. I've enabled AndroidX as per the official docs but now I'm getting run time errors when trying to inflate views via the corresponding auto generated Binding classes that are created from enabling databinding in the modules gradle.

Digging into the autogenerated source I came across this method, which is the one which is causing the code to throw:

   public List<DataBinderMapper> collectDependencies() {
        ArrayList<DataBinderMapper> result = new ArrayList(1);
        result.add(new com.android.databinding.library.baseAdapters.DataBinderMapperImpl());
        return result;
    }

As you can see, the auto generated code is attempting to instantiate an class from the com.android.databinding package, but that package doesn't exist in the output APK as I have removed the support dependencies from my gradle (because AndroidX is supposed to replace them). I can see that androidx has a databinding package so I am assuming that the autogenerated code above should be referencing androidx.databinding package instead, but it doesn't.

Is this a bug in the tooling or have I misconfigured something?

Here is my gradle file (some bits omitted for security reasons):

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'

//These variable refer to release builds so make sure they are correct. If you need to override them
//for some specific development needs then use variables that can be passed to gradle on command line.
String releaseVersionName = '1.0.0'
int releaseVersionCode = 1
int releaseMinSdk = 18
int releaseCompileSdkVersion = 28

android {
    //Added as separate variable so it can be overridden from IDE to speed up compilation time
    //Set minimum compilation sdk.
    int developMinSdk = rootProject.hasProperty('productMinSdk') ?
            rootProject.productMinSdk.toInteger() : releaseMinSdk
    String developProductVersionName = rootProject.hasProperty('productVersionName') ?
            rootProject.productVersionName : releaseVersionName
    int developProductVersionCode = System.getenv("BUILD_ID") as Integer ?: releaseVersionCode
    int developCompileSdk = rootProject.hasProperty('productCompileSdk') ?
            rootProject.productCompileSdk.toInteger() : releaseCompileSdkVersion

    defaultConfig {
        applicationId "..."
        compileSdkVersion developCompileSdk
        minSdkVersion developMinSdk
        targetSdkVersion developCompileSdk
        versionCode developProductVersionCode
        versionName developProductVersionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    signingConfigs {
       ...
    }

    sourceSets {
        ...
    }

    buildTypes {
        debug {
            signingConfig signingConfigs.release
            dexOptions {
                jumboMode = true
                javaMaxHeapSize "1g"
            }
            multiDexEnabled true
            matchingFallbacks = ['debug', 'release']
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            dexOptions {
                jumboMode = true
                javaMaxHeapSize "1g"
            }
        }
    }

    flavorDimensions "default"

    productFlavors {
        //noinspection GroovyMissingReturnStatement
        develop {
            applicationIdSuffix ".develop"
            dimension "default"
            sourceSets {
                develop.java.srcDirs += 'src/develop/kotlin'
            }
        }

        //Normal build for release
        //noinspection GroovyMissingReturnStatement
        playstore {
            //In this flavour we use release* variable explicitly so they cannot be
            //overridden by mistake
            //Force min sdk version from the global variable
            minSdkVersion releaseMinSdk
            //Force version name from the global variables
            versionName releaseVersionName
            //Force version code from the global variable
            versionCode releaseVersionCode
            //Force compile and target sdk versions from the global variable
            compileSdkVersion releaseCompileSdkVersion
            targetSdkVersion releaseCompileSdkVersion
            dimension "default"
            sourceSets {
                playstore.java.srcDirs += 'src/playstore/kotlin'
            }
        }
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Runtime dep versions
    def condecoCoreVersion = "0.1.3"
    def appCenterVersion = "1.9.0"
    def thirtyinchVersion = '0.9.0'
    def stethoVersion = "1.5.0"
    def leakCanaryVersion = '1.5.4'
    def hahaVersion = "1.3"
    def multiDexVersion = "2.0.0"
    def constraintLayoutVersion = "1.1.3"

    // Test dep versions
    def jUnitVersion = "4.12"

    // Std lib dependency
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: "$kotlin_version"
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: "$kotlin_version"

    // Multidex dependency
    implementation "androidx.multidex:multidex:$multiDexVersion"

    // Junit dependency for testing
    testImplementation "junit:junit:$jUnitVersion"
}

And here is my gradle.properties file:

# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official

# Use androidX to replace requirement for
# Support libraries to be imported via gradle
android.useAndroidX=true

# Jetifier automatically updates dependancy binaries
# To swap out support lib for androix
android.enableJetifier=true

EDIT: And here is my project level gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        kotlin_version = '1.2.71'
        gradle_plugin_version = '3.2.1'
    }

    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:$gradle_plugin_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
like image 360
Thomas Cook Avatar asked Nov 20 '18 11:11

Thomas Cook


People also ask

Is Android databinding deprecated?

Recently Android has announced that with Kotlin 1.4. 20, their Android Kotlin Extensions Gradle plugin will be deprecated and will no longer be shipped in the future Kotlin releases. Android Kotlin Extensions plugin brought with it two very cool features : Synthetics let you replace calls to findViewById with kotlinx.

Is Data Binding good in Android?

Using data binding can lead to faster development times, faster execution times and more readable and maintained code. Android data binding generates binding classes at compile time for layouts.

What is Android data binding?

The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically. Layouts are often defined in activities with code that calls UI framework methods.


1 Answers

Ok, finally cracked this.

The issue was I was using a library which depended on android databinding (and not androidx databinding).

Even though I had enabled Jetifier in my gradle.properties file, for some reason the libraries binary wasn't having android databinding swapped out for the corresponding androidx version. Fortunately, the library was in house, so I've updated the library to migrate to androidx and this whole nightmare resolved itself.

Thanks for all the suggestions, hope this answer helps anyone with a similar problem as it's cost me 2 working days to figure out!

like image 147
Thomas Cook Avatar answered Oct 01 '22 03:10

Thomas Cook