11

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

Gregriggins36
  • 905
  • 10
  • 20

2 Answers2

8

The missing piece is to set a Lifecycle Owner.

binding.setLifecycleOwner(parent) //parent should be a fragment or an activity
fukuda
  • 416
  • 3
  • 6
  • Thanks Rafael, this worked! I'm getting the activity with the following code `val activity: AppCompatActivity = (context as ContextThemeWrapper).baseContext as AppCompatActivity` `binding.setLifecycleOwner(activity)` – Gregriggins36 May 03 '18 at 17:10
  • How to support two way databinding? – CodingTT Jun 23 '20 at 09:20
6

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)
}
Juan Mendez
  • 2,658
  • 1
  • 27
  • 23