etiennelenhart / Eiffel

Redux-inspired Android architecture library leveraging Architecture Components and Kotlin Coroutines
MIT License
211 stars 14 forks source link

Context in BaseObservable #125

Closed eugenio1590 closed 4 years ago

eugenio1590 commented 4 years ago

Hi @etiennelenhart after a long time I continue using this library. I know that you have introduced new changes, but speaking of version 4.1.0, how can I get the reference to the context within a BindingState? This is an example:

class CatBindingState : BaseObservable(), BindingState<CatViewState> {

  override fun refresh(state: CatViewState) {
      context.getString() ......
  }

}
etiennelenhart commented 4 years ago

Hey @eugenio1590, thanks for your question.

Since the BindingState is part of an Activity or Fragment you should, in theory, be fine with injecting a Context in the state's constructor.

That being said, it's probably easier and safer to not depend on a Context in your BindingState. Have a look at the BindingState section in the Readme. You basically simply provide the resource IDs instead of the actual resolved resources:

class AngryCatBindingState : BindingState<AngryCatViewState> {
    val soundResId = ObservableInt(0)
    val catResId = ObservableInt(R.drawable.cat)

    override fun refresh(state: AngryCatViewState) {
        soundResId.set(if (state.meowing) R.string.meow else 0)
        catResId.set(if (state.meowing) R.drawable.angry_cat else R.drawable.cat)
    }
}

These IDs are perfectly usable in your layout using Data Binding:

<layout ...>

        <data>
            <variable
                name="viewmodel"
                type="com.fluffycat.friendlymittens.angrycat.viewmodel.AngryCatViewModel"/>

            <variable
                name="state"
                type="com.fluffycat.friendlymittens.angrycat.state.AngryCatBindingState"/>
        </data>

        ...

            <ImageView
                ...
                app:imageResource="@{state.catResId}"/>

            <TextView
                ...
                android:text="@{state.soundResId}"/>

        ...

</layout>

Hope this answers your question. 🙂

eugenio1590 commented 4 years ago

Hi @etiennelenhart I see. I can try to add a context in the constructor of the class. I need to get a string but with parameters, so I need the context to do it. Thanks for your help.

etiennelenhart commented 4 years ago

Ah, in that case note, that there also is a context available in Binding expressions:

android:text='@{context.getString(id)}"

So you should be able to combine both approaches without the need for injecting a context.

eugenio1590 commented 4 years ago

Yes, I considered that implementation using the context in the binding but the logic is complicated. Using the context in the constructor of the BindingState is worked for me. Thanks.