Steps to reproduce my problem
Create a custom view
class VideoTrimmerView(context: Context, attrs: AttributeSet) : View(context) {
private val backgroundPaint: Paint = Paint().apply {
color = Color.BLACK
}
override fun draw(canvas: Canvas?) {
super.draw(canvas)
canvas?.drawRect(Rect(0, 0, width, height), backgroundPaint)
}
}
Add <declare-styleable> resources to the project
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="VideoTrimmerView" />
</resources>
Add layout xml file activity_video_trimmer.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VideoTrimmerActivity">
<com.udara.developer.myapp.videotrimmer.VideoTrimmerView
android:id="#+id/video_trimmer_view"
android:layout_width="match_parent"
android:layout_height="64dp"
app:layout_constraintBottom_toBottomOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="#+id/open_video_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Video"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Enable view binding in module level build.gradle
android {
buildFeatures {
viewBinding true
}
}
Use view bindings to access views
class VideoTrimmerActivity : AppCompatActivity() {
private lateinit var binding: ActivityVideoTrimmerBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityVideoTrimmerBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
}
I get the following error when running the app
Caused by: java.lang.NullPointerException: Missing required view with ID: com.udara.developer.my_app:id/video_trimmer_view
The problem only happens when custom views are used. How to solve this issue?
I have invoked super constructor without attrs parameter.
Previous constructor version
class VideoTrimmerView(context: Context, attrs: AttributeSet) : View(context) {
}
After adding attrs parameter
class VideoTrimmerView(context: Context, attrs: AttributeSet) : View(context, attrs) {
}
In the android documentation it just tells
To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a Context and an AttributeSet object as parameters.
Now the problem is solved!
I have 2 Groups in my layout which control the visibility of my Views.
However, I cannot set their visibility via DataBinding:
<layout>
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="co.aresid.book13.fragments.trackinglist.TrackingListViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
...
<androidx.constraintlayout.widget.Group
android:id="#+id/content_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent ? View.VISIBLE : View.GONE, default=gone}"
app:constraint_referenced_ids="tracking_list_recycler_view"
/>
<androidx.constraintlayout.widget.Group
android:id="#+id/loading_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent ? View.GONE : View.VISIBLE, default=visible}"
app:constraint_referenced_ids="progress_circular"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The hideLoadingAndShowContent variable is a LiveData which gets its value from a corresponding MutableLiveData in my ViewModel:
private val _hideLoadingAndShowContent = MutableLiveData<Boolean>()
val hideLoadingAndShowContent: LiveData<Boolean>
get() = _hideLoadingAndShowContent
This LiveData is only set in the ViewModel and does not occur in the Fragment class.
In the Fragment class, I have also set the binding.lifecycleOwner:
binding.lifecycleOwner = viewLifecycleOwner
What detail am I missing out?
I forgot to pass the ViewModel to the layout binding in my Fragment class:
binding.viewModel = viewModel
Because that android:visibility does not support binding variable observation,
You can create BindingAdapter this way
#BindingAdapter("mutableVisibility")
fun setMutableVisibility(view: View, visibility: MutableLiveData<Boolean>) {
val owner = (view.getParentActivity() ?: view.context) as LifecycleOwner
if (owner != null) {
visibility.observe(
owner,
Observer { value ->
view.visibility = if(value) View.VISIBLE else View.GONE
})
}
}
Utility function for getting activity from view.
fun View.getParentActivity(): AppCompatActivity?{
var context = this.context
while (context is ContextWrapper) {
if (context is AppCompatActivity) {
return context
}
context = context.baseContext
}
return null
}
Then in your XML you can do it like
<androidx.constraintlayout.widget.Group
android:id="#+id/content_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent}"
app:constraint_referenced_ids="tracking_list_recycler_view"
/>
FragmentHome load layout_home.xml, and layout_home.xml displays a recyclerview and a button named btnMain
recyclerview include the item layout layout_voice_item.xml, it displays a button named btnChild。
I use displayCheckBox : LiveData<Boolean> to control whether both btnMain and btnChild are shown or not with the code android:visibility="#{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}".
I find btnMain can be shown or not when I change the value of displayCheckBox, but btnChild keep to show, why?
FragmentHome.kt
class FragmentHome : Fragment() {
private lateinit var binding: LayoutHomeBinding
private val mHomeViewModel by lazy {
getViewModel {
HomeViewModel(provideRepository(mContext))
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(
inflater, R.layout.layout_home, container, false
)
binding.lifecycleOwner = this.viewLifecycleOwner
binding.aHomeViewModel=mHomeViewModel
val adapter = VoiceAdapters(mHomeViewModel)
binding.mvoiceList.adapter=adapter
mHomeViewModel.listVoiceBySort.observe(viewLifecycleOwner){
adapter.submitList(it)
}
...
return binding.root
}
}
HomeViewModel.kt
class HomeViewModel(private val mDBVoiceRepository: DBVoiceRepository) : ViewModel() {
private val _displayCheckBox = MutableLiveData<Boolean>(true)
val displayCheckBox : LiveData<Boolean> = _displayCheckBox
fun setCheckBox(isDisplay:Boolean){
_displayCheckBox.value = isDisplay
}
...
}
VoiceAdapters.kt
class VoiceAdapters (private val aHomeViewModel: HomeViewModel):
ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {
...
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VoiceViewHolder {
return VoiceViewHolder(
LayoutVoiceItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
override fun onBindViewHolder(holder: VoiceViewHolder, position: Int) {
val aMVoice = getItem(position)
holder.bind(aHomeViewModel, aMVoice)
}
inner class VoiceViewHolder (private val binding: LayoutVoiceItemBinding):
RecyclerView.ViewHolder(binding.root) {
fun bind(mHomeViewModel: HomeViewModel, aMVoice: MVoice) {
binding.aHomeViewModel = mHomeViewModel
binding.executePendingBindings()
}
}
...
}
class MVoiceDiffCallback : DiffUtil.ItemCallback<MVoice>() {
...
}
layout_home.xml
<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>
<import type="android.view.View" />
<variable name="aHomeViewModel"
type="info.dodata.voicerecorder.viewcontrol.HomeViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/mvoice_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/layout_voice_item"
/>
<Button
android:id="#+id/btnMain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="#{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
layout_voice_item.xml
<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="aHomeViewModel"
type="info.dodata.voicerecorder.viewcontrol.HomeViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/btnChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="#{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}"
/>
</LinearLayout>
</layout>
Giving a LifecycleOwner to LayoutVoiceItemBinding might helps.
voiceViewHolder.binding.lifecycleOwner = yourLifecycleOwner
The view holder pattern was not always part of android and before its wide adoption, a naive list implementation would have resulted in an inflated view rendered for each value in the submitted list. That is extremely memory inefficient.
With the adoption of a view holder pattern, views (the visual items) are only inflated up to the maximum that can be visible on the screen (and one or two extra for smooth scrolling)
The adapter however needs to be made aware of changes in the list's data.
https://developer.android.com/guide/topics/ui/layout/recyclerview#Adapter
If the list needs an update, call a notification method on the
RecyclerView.Adapter object, such as notifyItemChanged(). The layout
manager then rebinds any affected view holders, allowing their data to
be updated.
Observing the displayCheckBox : LiveData<Boolean> and calling adapter.notifyItemChanged might be the issue at hand.
I leave with another reference reiterating that view binding will not observe the live data but reduces the boilerplate code.
https://medium.com/androiddevelopers/android-data-binding-recyclerview-db7c40d9f0e4
What’s Left?
All the boilerplate from the RecyclerView is now handled
and all you have left to do is the hard part: loading data off the UI
thread, notifying the adapter when there is a data change, etc.
Android Data Binding only reduces the boring part.
I have checked many answers to find my issue however I was not successful. I have an activity that holds a compound drawable.
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.my.profile.widgets.ProfileWidget
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
....
</LinearLayout>
</layout>
This is my ProfileWidget:
class ProfileWidget #JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
#Inject lateinit var viewModel: ProfileWidgetViewData
#Inject lateinit var viewActions: ProfileWidgetActions
private val binding: WidgetProfileBinding = DataBindingUtil.inflate(
LayoutInflater.from(context), R.layout.widget_profile, this, true)
// private val binding = WidgetProfileBinding.inflate(LayoutInflater.from(context), this, true)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
setupDependencyInjection()
setupDataBinding()
viewActions.testUI()
}
private fun setupDependencyInjection() {
(context as ProfileActivity).getProfileComponent()?.inject(this)
}
private fun setupDataBinding() {
binding.viewModel = viewModel
}
}
This is its layout:
<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>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.my.profile.widgets.ProfileWidgetViewData" />
</data>
<LinearLayout
android:id="#+id/profilesContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#FF0000"
>
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="profile 1"
android:visibility="#{viewModel.textView_1.get() ? View.VISIBLE : View.INVISIBLE}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="profile 2"
android:visibility="#{viewModel.textView_2.get() ? View.VISIBLE : View.INVISIBLE}"/>
</LinearLayout>
</layout>
Finally my ViewModel class supposed to make TextViews
visible/invisible.
interface ProfileWidgetViewData {
val textView_1: ObservableBoolean
val textView_2: ObservableBoolean
}
interface ProfileWidgetActions {
fun testUI()
}
class ProfileWidgetViewModelImpl : ProfileWidgetViewData, ProfileWidgetActions {
override val textView_1 = ObservableBoolean(false)
override val textView_2 = ObservableBoolean(false)
override fun testUI() {
setProfilesContainerVisibility(true)
setAddProfileContainerVisibility(true)
}
private fun setProfilesContainerVisibility(isVisible: Boolean) {
textView_1.set(isVisible)
}
private fun setAddProfileContainerVisibility(isVisible: Boolean) {
textView_2.set(isVisible)
}
}
Unfortunately I don't see anything wrong in above codes. When I launch
the app, those two TextView are Invisible although I have set them to be visible.
Check below is added or not in build.gradle(obviously you already added)
apply plugin: 'kotlin-kapt'
android {
dataBinding {
enabled = true
}
}
dependencies {
kapt "com.android.databinding:compiler:3.1.3"
}
And add below line in your xml file for visibility or invisible
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="profile 1"
android:visibility="#{safeUnbox(viewModel.textView_1) ? View.VISIBLE : View.INVISIBLE}"/>
The Android data binding guide discusses binding values within an activity or fragment, but is there a way to perform data binding with a custom view?
I would like to do something like:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mypath.MyCustomView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>
with my_custom_view.xml:
<layout>
<data>
<variable
name="myViewModel"
type="com.mypath.MyViewModelObject" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{myViewModel.myText}" />
</LinearLayout>
</layout>
While it appears possible to do this by setting custom attributes on the custom view, this would quickly become cumbersome if there's a lot of values to bind.
Is there a good way to accomplish what I'm trying to do?
In your Custom View, inflate layout however you normally would and provide a setter for the attribute you want to set:
private MyCustomViewBinding mBinding;
public MyCustomView(...) {
...
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = MyCustomViewBinding.inflate(inflater);
}
public void setMyViewModel(MyViewModelObject obj) {
mBinding.setMyViewModel(obj);
}
Then in the layout you use it in:
<layout xmlns...>
<data>
<variable
name="myViewModel"
type="com.mypath.MyViewModelObject" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mypath.MyCustomView
android:id="#+id/my_view"
app:myViewModel="#{myViewModel}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>
</layout>
In the above, an automatic binding attribute is created for app:myViewModel because there is a setter with the name setMyViewModel.
Data binding works even with merge only parent had to be "this" and attach to parent true.
binding = DataBindingUtil.inflate(inflater, R.layout.view_toolbar, this, true)
First, don't do this if this custom view is already being <include> in another layout, such as activity etc. You'll just get an exception about the tag being unexpected value. The data binding already ran the binding on it, so you're set.
Did you try using onFinishInflate to run the bind? (Kotlin example)
override fun onFinishInflate() {
super.onFinishInflate()
this.dataBinding = MyCustomBinding.bind(this)
}
Keep in mind that if you use the binding in your view, it won't be able to be created programmatically, at least it would be very convoluted to support both even if you can.
Following the solution presented by george the graphical editor in android studio was no longer able to render the custom view. The reason is, that no view is actually inflated in the following code:
public MyCustomView(...) {
...
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = MyCustomViewBinding.inflate(inflater);
}
I suppose that the binding handles the inflation, however the graphical editor did not like it.
In my specific use case I wanted to bind a single field and not an entire view model. I came up with (kotlin incoming):
class LikeButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
val layout: ConstraintLayout = LayoutInflater.from(context).inflate(R.layout.like_button, this, true) as ConstraintLayout
var numberOfLikes: Int = 0
set(value) {
field = value
layout.number_of_likes_tv.text = numberOfLikes.toString()
}
}
The like button consists of an image and a text view. The text view holds the number of likes, which I want to set via data binding.
By using the setter for numberOfLikes as an attribute in the following xml, data binding automatically makes the association:
<views.LikeButton
android:id="#+id/like_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:numberOfLikes="#{story.numberOfLikes}" />
Further reading: https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47
Today, I want to use the dataBinding on my Custom View class. But I don't know how to create data binding to my class. so I search the answer on StackOverflow.
Firstly I try the answer:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = BottomBarItemCustomViewBinding.inflate(inflater);
but, I found this is not working for my code
so I change another method:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);
It's working for me.
the complete code is:
bottom_bar_item_custom_view.xml
<data>
<variable
name="contentText"
type="String" />
<variable
name="iconResource"
type="int" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="#+id/bottomBarItemIconIv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="2dp"
android:src="#{iconResource}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/bottomBarItemContentTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#{contentText}"
android:textColor="#color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/bottomBarItemIconIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
BottomBarItemCustomView.java
public class BottomBarItemCustomView extends ConstraintLayout {
public BottomBarItemCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
//use dataBinding on custom view.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BottomBarItemCustomView);
int iconResourceId = typedArray.getResourceId(R.styleable.BottomBarItemCustomView_bottomBarIconResource, R.drawable.my_account_icon);
binding.setIconResource(iconResourceId);
String contentString = typedArray.getString(R.styleable.BottomBarItemCustomView_bottomBarContentText);
if (contentString != null) {
binding.setContentText(contentString);
}
typedArray.recycle();
}
hope is useful for you!
In Kotlin we can directly use ViewBinding:
class BenefitView(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
init {
val binding = BenefitViewBinding.inflate(LayoutInflater.from(context), this, true)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.BenefitView)
binding.image.setImageDrawable(attributes.getDrawable(R.styleable.BenefitView_image))
binding.caption.text = attributes.getString(R.styleable.BenefitView_text)
attributes.recycle()
}
}
There are some good answers on here already, but I wanted to offer what I believe to be the simplest.
Create your custom control with the layout tags surrounding it, just like any other layout. See the following toolbar for example. this gets used in each of the activity classes
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="YACustomPrefs" type="com.appstudio35.yourappstudio.models.YACustomPreference" />
</data>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/YATheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
app:popupTheme="#style/YATheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Now this custom layout is a child of every Activity. You simply treat it as such in the onCreate binding setup.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.toolbarMain?.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.navHeader?.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.activity = this
binding.iBindingRecyclerView = this
binding.navHeader?.activity = this
//local pointer for notify txt badge
txtNotificationCountBadge = txtNotificationCount
//setup notify if returned from background so we can refresh the drawer items
AppLifeCycleTracker.getInstance().addAppToForegroundListener(this)
setupFilterableCategories()
setupNavigationDrawer()
}
Notice I set the children's content at the same time I do the parent and it is all done through dot notation access. As long as the files are surrounded with layout tags and you named them, it is simple to do.
Now if the custom class has it's own associated code inflation, then it can easily just do it's own binding in it's onCreate or constructor, but you get the picture. If you have your own class just throw the following in the constructor to match it's named binding class. It follows the name convention of the layout file pascal cased, so it's easy to find and auto fill.
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = NameOfCustomControlBinding.inflate(inflater);
Hope that helps.
I faced the same issue when I am trying to add a child views to a LinearLayout inside my host fragment(Nested fragment UI/UX)
here is my solution
var binding: LayoutAddGatewayBinding? = null
binding = DataBindingUtil.inflate(layoutInflater, R.layout.layout_add_gateway,
mBinding?.root as ViewGroup?, false)
binding?.lifecycleOwner=this
val nameLiveData = MutableLiveData<String>()
nameLiveData.value="INTIAL VALUE"
binding?.text=nameLiveData
Here mBinding is child fragment ViewDataBinding object and I have used nameLiveData for two-way databinding