Akshata
Akshata

Reputation: 1025

Databinding and BaseObserver - Android MVVM

I have a textfield which is databound to a view model like the xml here and I want the UI to update the txtProvider field on click of the cardView. How should I notify the change to the view from my viewmodel?

<layout xmlns:bind="http://schemas.android.com/tools">
<data>
    <variable name="viewmodel"        
              type="io.leapingwolf.myapp.viewmodel.MyViewModel"/>
   <variable
    name="myModel"
    type="io.leapingwolf.myapp.models.MyModel"/>
</data>
    <android.support.v7.widget.CardView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"   
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/cardView"
        app:cardCornerRadius="5dp"
        app:cardUseCompatPadding="true"
        android:onClick="@{viewmodel.onClickModel}">
        <TextView
            android:id="@+id/txtProvider"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:text="@{myModel.provider}"
            android:textColor="@android:color/black"
            android:textSize="15sp" />
    </android.support.v7.widget.CardView>
</layout>

In MyViewModel(which extends BaseObserver class), I have

fun onClickModel() : View.OnClickListener {
        val viewOnClick = View.OnClickListener { v ->
                                myModel!!.provider = "name changed"
                                notifyPropertyChanged(BR.myModel)
                                Toast.makeText(context,"clicked:" + myModel!!.provider , Toast.LENGTH_SHORT).show()}
                                return viewOnClick
        }

My data class :

data class MyModel(
        val type: String?,
        var  provider: String? 
) : AutoParcelable

Upvotes: 4

Views: 2951

Answers (4)

user1884811
user1884811

Reputation: 323

In your MyModel.kt file

class MyModel(
        @get:Bindable
        var provider: String = ""
) : BaseObservable() {
    fun updateText(str:String){
        provider = str
        notifyPropertyChanged(BR.counter)
    }
}

and then in your layout.xml

android:onClick="@{() -> myModel.updateText(`YOUR TEXT`)}"

Rebuild your project if you cannot get BR.counter autocomplete working

Upvotes: 1

Akshata
Akshata

Reputation: 1025

I got it working in Kotlin using the @Bindable in the viewmodel like below.Took me a while to understand how to use @Bindable in Kotlin syntax. The property BR.provider was not getting generated till i got the @Bindable syntax right.

fun onClickModel(): View.OnClickListener {
    val viewOnClick = View.OnClickListener {
        route!!.provider = "name changed"
        notifyPropertyChanged(BR.provider)
    }
    return viewOnClick
}

val provider: String
    @Bindable
    get() {
        Log.d("Utils", "get property")
        return route!!.provider!!
    }

Upvotes: 2

Akshata
Akshata

Reputation: 1025

It might be more of a kotlin issue. When I initialise the provider String as ObservableField as

var provider = ObservableField<String>()
init{
    provider = route.provider as ObservableField<String>
}

I get an error at runtime java.lang.String cannot be cast to android.databinding.ObservableField

I will try posting it on the kotlin discussion site and seek some answers.

Upvotes: 0

yennsarah
yennsarah

Reputation: 5517

I'll use a java syntax, because I'm not that fluent with kotlin:

You need to declare your MyModel or the provider with DataBinding to enable the binding. Use a @Bindable on getter, and call notifyPropertyChangedin the setter:

@Bindable
public String getProvider() {
    return this.provider;
}

public void setProvider(String provider) {
    this.lastName = lastName;
    notifyPropertyChanged(BR.provider);
}

or make your MyModel extend BaseObservable, or since you have a viewmodel, create a ObservableField<String> or even a ObservableField<MyModel>:

//in your viewmodel:
private ObservableField<MyModel> modelField = new ObservableField<MyModel>();

Set the value in the constructor of your viewmodel, create a getter and reference this in your xml.

Upvotes: 1

Related Questions