Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 487
Gregriggins36 Avatar asked May 02 '18 21:05

Gregriggins36


2 Answers

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)
}
like image 183
Juan Mendez Avatar answered Oct 02 '22 10:10

Juan Mendez


The missing piece is to set a Lifecycle Owner.

binding.setLifecycleOwner(parent) //parent should be a fragment or an activity
like image 40
fukuda Avatar answered Oct 02 '22 08:10

fukuda