Databinding not work together with viewbinding in Kotlin
Asked Answered
H

3

8

Android Studio 3.6

build.gradle:

buildscript {
    ext.kotlin_version = '1.3.50'
    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.0-beta01'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

in app/build.gradle:

android {
    viewBinding.enabled = true
    dataBinding {
        enabled = true
    }

in my activity:

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager2.widget.ViewPager2

import com.myproject.BuildConfig
import com.myproject.R
import com.myproject.adapter.CustomFragmentStateAdapter
import com.myproject.databinding.QrBluetoothSwipeActivityBinding
import com.myproject.ui.fragment.BluetoothPageFragment
import com.myproject.ui.fragment.QrPageFragment
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableInt

class QRBluetoothSwipeActivity : AppCompatActivity() {
    private lateinit var viewBinding: QrBluetoothSwipeActivityBinding
    var positionObservable = ObservableInt()

    companion object {
        private val TAG = QRBluetoothSwipeActivity::class.java.name
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)  

         // databinding init
        val binding = DataBindingUtil.setContentView<QrBluetoothSwipeActivityBinding>(
            this, R.layout.qr_bluetooth_swipe_activity
        )
        binding.setHandler(this)

        // viewbinding init
        viewBinding = QrBluetoothSwipeActivityBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)

        init()
    }

 private fun init() {
        val customFragmentStateAdapter = CustomFragmentStateAdapter(this)
        customFragmentStateAdapter.addFragment(QrPageFragment())
        customFragmentStateAdapter.addFragment(BluetoothPageFragment())
        viewBinding.viewPager2.adapter = customFragmentStateAdapter

        viewBinding.viewPager2.registerOnPageChangeCallback(object :
            ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                if (BuildConfig.DEBUG) {
                    Log.d(TAG, "registerOnPageChangeCallback: position = $position")
                }
                positionObservable.set(position)
            }
        })
    }

my qr_bluetooth_swipe_activity.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">

    <data>

        <import type="android.view.View" />

        <variable
            name="handler"
            type="com.myproject.actviity.QRBluetoothSwipeActivity" />

    </data>

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

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@+id/bottonContainer"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/bottonContainer"
            android:layout_width="0dp"
            android:layout_height="104dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/qrBottonMainContainer"
                android:layout_width="0dp"
                android:layout_height="104dp"
                android:visibility="@{handler.positionObservable == 0 ? View.GONE: View.VISIBLE}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"/>

After start app then success swipe viewpager2. And as result success show the next message:

10-25 14:25:24.991 D/com.myproject.actviity.QRBluetoothSwipeActivity(23012): registerOnPageChangeCallback: position = 0

nice. But qrBottonMainContainer not hide. Why?

P.S. If I remove this:

viewBinding = QrBluetoothSwipeActivityBinding.inflate(layoutInflater)
setContentView(viewBinding.root)

then success work.

why?

Hammer answered 25/10, 2019 at 11:26 Comment(0)
M
19

You can't use them togheter in the same layout.

ViewBinding is a subset of what DataBinding can do and should be used if you want to replace libraries like ButterKnife, KotterKnife or KAE (Kotlin Android Extensions) but don't want to invest in databinding refactoring.

If you use DataBinding you already have the id reference of the views composing the layout in your binding object. Something like binding.myTextView.

Remember that:

  • The data binding library only processes data binding layouts created using the <layout> tag.
  • View binding doesn't support layout variables or layout expressions, so it can't be used to bind layouts with data in XML.

As per the documentation here

PS: In your specific case you can't use <layout> tags with ViewBinding

Mcgrew answered 25/10, 2019 at 12:37 Comment(4)
I added my answerHammer
According to the linked documentation, they can be used together. "it is best in some cases to use both view binding and data binding in a project"Lowbred
@Lowbred The documentation just say that you should choose which one to use based on the layout needs/specification. But you can't use them together on the same layout still. The restriction is per-layout and not per-projectMcgrew
Ah ok. I misinterpreted your post to mean that you can't use them together in the same project.Lowbred
F
2

If You want to use View Binding & Data Binding Together in a single layout you need to use only data binding because view binding is the subset of data binding data binding provide the functionality of view binding.

The difference between the two is that view binding is only for view references and not for binding UI with data sources.

android {
buildFeatures {
    dataBinding true
  }
}




   <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
    <variable
        name="viewmodel"
        type="com.myapp.data.ViewModel" />
</data>

</layout>




val dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
dataBinding.executePendingBindings()
dataBinding.tvName.text="View Binding"
Follow answered 4/6, 2021 at 12:11 Comment(0)
H
1

Here solution without viewbinding

android {
    dataBinding {
        enabled = true
    }

in activity:

     import android.os.Bundle
        import android.util.Log
        import androidx.appcompat.app.AppCompatActivity
        import androidx.viewpager2.widget.ViewPager2

        import com.myproject.BuildConfig
        import com.myproject.R
        import com.myproject.adapter.CustomFragmentStateAdapter
        import com.myproject.ui.fragment.BluetoothPageFragment
        import com.myproject.ui.fragment.QrPageFragment
        import androidx.databinding.DataBindingUtil
        import androidx.databinding.ObservableInt
        import com.myproject.databinding.QrBluetoothSwipeActivityBinding

    class QRBluetoothSwipeActivity : AppCompatActivity() {
        private lateinit var dataBinding: QrBluetoothSwipeActivityBinding
        var positionObservable = ObservableInt()

        companion object {
            private val TAG = QRBluetoothSwipeActivity::class.java.name
        }

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            dataBinding = DataBindingUtil.setContentView<QrBluetoothSwipeActivityBinding>(
                this, R.layout.qr_bluetooth_swipe_activity
            )
            dataBinding.setHandler(this)
            init()
        }

        private fun init() {
        val customFragmentStateAdapter = CustomFragmentStateAdapter(this)
        customFragmentStateAdapter.addFragment(QrPageFragment())
        customFragmentStateAdapter.addFragment(BluetoothPageFragment())
        dataBinding.viewPager2.adapter = customFragmentStateAdapter

        dataBinding.viewPager2.registerOnPageChangeCallback(object :
            ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                if (BuildConfig.DEBUG) {
                    Log.d(TAG, "registerOnPageChangeCallback: position = $position")
                }
                positionObservable.set(position)
            }
        })
    }
}

And now it's work ONLY with databinding.

Nice.

Thanks @MatPag

Hammer answered 25/10, 2019 at 13:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.