Search code examples
androiddata-bindingkotlinandroid-custom-viewandroid-viewmodel

Android data binding inject ViewModel in custom view


I'm going off this stackoverflow answer https://stackoverflow.com/a/34817565/4052264 to tie a data object to a custom view. However, after everything's set up my view is not being updated with the data and instead the TextView stays blank. Here's my code (simplified, for the sake of fitting in here):

activity_profile.xml:

<layout xmlns...>
    <data>
        <variable name="viewModel" type="com.example.ProfileViewModel"/>
    </data>
    <com.example.MyProfileCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:viewModel="@{viewModel}">
</layout>


view_profile.xml:

<layout xmlns...>
    <data>
        <variable name="viewModel" type="com.example.ProfileViewModel"/>
    </data>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{viewModel.name}">
</layout>


MyProfileCustomView.kt:

class MyProfileCustomView : FrameLayout {
    constructor...

    private val binding: ViewProfileBinding = ViewProfileBinding.inflate(LayoutInflater.from(context), this, true)

    fun setViewModel(profileViewModel: ProfileViewModel) {
        binding.viewModel = profileViewModel
    }
}



ProfileViewModel.kt:

class ProfileViewModel(application: Application) : BaseViewModel(application) {
    val name = MutableLiveData<String>()

    init {
        profileManager.profile()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(::onProfileSuccess, Timber::d)
    }

    fun onProfileSuccess(profile: Profile) {
        name.postValue(profile.name)
    }
}

Everything works fine, the API call to profileManager.profile() is successful, the ViewProfileBinding class is successfully created with the right setup. The issue is when I do name.postValue(profile.name) the view is not updated with the value of profile.name


Solution

  • The missing piece is to set a Lifecycle Owner.

    binding.setLifecycleOwner(parent) //parent should be a fragment or an activity