Gregriggins36
Gregriggins36

Reputation: 943

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

Upvotes: 11

Views: 9296

Answers (2)

Juan Mendez Escobar
Juan Mendez Escobar

Reputation: 2757

The answered helped me and want to throw a util method you can add to get the LifeCycleOwner

fun getLifeCycleOwner(view: View): LifecycleOwner? {
    var context = view.context

    while (context is ContextWrapper) {
        if (context is LifecycleOwner) {
            return context
        }
        context = context.baseContext
    }

    return null
}

In your view:

getLifeCycleOwner(this)?.let{
   binding.setLifecycleOwner(it)
}

Upvotes: 6

fukuda
fukuda

Reputation: 416

The missing piece is to set a Lifecycle Owner.

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

Upvotes: 8

Related Questions