androidandroid-databinding

DataBinding not working in module


I'm using data binding within my app. I have an application module and the data binding is working successfully.

However, I also have a 'home-module' I'm trying to use the same techniques, but the data binding is erroring in the xml with the following:

Error:(63, 34) No resource type specified (at 'onClick' with value '@{viewModel::onButtonClicked}').

I've found this bug report which suggests this was an issue but it's been fixed.

I can't see any issues with the code, I think the problem is because it's in the library module.

Is there anything I can do to get this working?

home-module

activity_home.xml

<?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="viewModel" type="com.flowmellow.projectx.home.ui.viewmodel.HomeViewModel"/>
    </data>

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/home_screen"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.flowmellow.projectx.home.ui.viewmodel.HomeActivity">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>

        </android.support.design.widget.AppBarLayout>

        <android.support.constraint.ConstraintLayout
            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"
            android:id="@+id/content_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            tools:context="com.flowmellow.projectx.home.ui.viewmodel.HomeActivity">

            <TextView
                android:text="@string/activity_home_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/activity_home_title"
                android:textAppearance="@style/TextAppearance.AppCompat.Large"
                android:layout_marginStart="16dp"
                app:layout_constraintLeft_toLeftOf="parent"
                android:layout_marginLeft="16dp"
                android:layout_marginEnd="16dp"
                app:layout_constraintRight_toRightOf="parent"
                android:layout_marginRight="16dp"
                app:layout_constraintBottom_toTopOf="@+id/activity_home_button"
                android:layout_marginBottom="64dp" />

            <Button
                android:text="@string/activity_home_button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:id="@+id/activity_home_button"
                style="@style/Widget.AppCompat.Button.Colored"
                android:onClick="@{viewModel::onButtonClicked}"/>

        </android.support.constraint.ConstraintLayout>

    </android.support.design.widget.CoordinatorLayout>
</layout>

HomeActivity

public class HomeActivity extends AppCompatActivity {

    private HomeViewModel mHomeViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        final CustomSensorManager customSensorManager = new CustomSensorManager(sensorManager);
        mHomeViewModel = new HomeViewModel(customSensorManager);

        setBindingContentView(R.layout.activity_home);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

    private void setBindingContentView(@LayoutRes int layoutResID) {
        ActivityHomeBinding binding = DataBindingUtil.setContentView(this, layoutResID);
        binding.setViewModel(mHomeViewModel);
    }
}

HomeViewModel

public class HomeViewModel {

    private CustomSensorManager mSensorManager;

    public HomeViewModel(@NonNull CustomSensorManager sensorManager) {
        mSensorManager = sensorManager;
    }

    public void onButtonClicked(View view) {
        mSensorManager.scan(true);
    }
}

build.gradle

apply plugin: 'com.android.library'
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    dataBinding {
        enabled = true
    }
}
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')

    compile 'com.android.support:appcompat-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'
    compile 'com.android.support.constraint:constraint-layout:+'
}

Update:

Could be a bug. link

My problem:

enter image description here

The engine module has no UI, so the dependency was missed, makes a lot of sense now.


Solution

  • Say you have a multilevel module hierarchy like this in your app:

    Multilevel module hierarchy in Android

    In order for databinding to work module A, you have to make sure you enable databinding in the whole hierarchy from the root module into module A.

    That means you have to add:

    dataBinding {
        enabled = true
    }
    

    To the modules:

    It is important to remember that you do have to also enable databinding in module B, so all paths are covered.