airbnb / mavericks

Mavericks: Android on Autopilot
https://airbnb.io/mavericks/
Apache License 2.0
5.84k stars 498 forks source link

invalidate is called twice in the first invalidation #48

Closed yigit closed 6 years ago

yigit commented 6 years ago

when setState is called for the very first time, invalidate of the MvRxView (fragment) is called twice. It might also be realated to the fact that invalidate is not called for a fresh Fragment until setState is called. (i would expect at least 1 invalidate after initialization) The code below triggers a setState when user clicks on the text view. This is the log I receive:

08-23 21:14:03.900 8309-8338/com.birbit.android.devto D/MVRX: setting state to update 1535084043900
08-23 21:14:03.900 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084043900
08-23 21:14:03.901 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084043900
data class MyState(val text : String = "bar") : MvRxState
class MainViewModel(initialState : MyState) : BaseMvRxViewModel<MyState>(initialState, false) {
    fun updateValue() {
        setState {
            val newText = "update ${System.currentTimeMillis()}"
            Log.d("MVRX", "setting state to $newText")
            copy(text = newText)
        }
    }
}

class MainFragment : BaseMvRxFragment() {
    private val viewModel by fragmentViewModel(MainViewModel::class)
    override fun invalidate() {
        withState(viewModel) {
            Log.d("MVRX", "updating UI to ${it.text}")
            main_content.text = it.text
        }
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_main, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        main_content.setOnClickListener {
            viewModel.updateValue()
        }
    }
}
yigit commented 6 years ago

to be clear, consecutive setState calls trigger invalidate only once.

08-23 21:14:03.900 8309-8338/com.birbit.android.devto D/MVRX: setting state to update 1535084043900
08-23 21:14:03.900 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084043900
08-23 21:14:03.901 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084043900
08-23 21:19:11.827 8309-8338/com.birbit.android.devto D/MVRX: setting state to update 1535084351827
08-23 21:19:11.828 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084351827
08-23 21:19:15.234 8309-8338/com.birbit.android.devto D/MVRX: setting state to update 1535084355234
08-23 21:19:15.234 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084355234
08-23 21:19:15.912 8309-8338/com.birbit.android.devto D/MVRX: setting state to update 1535084355912
08-23 21:19:15.913 8309-8309/com.birbit.android.devto D/MVRX: updating UI to update 1535084355912
gpeal commented 6 years ago

I think it's because the first one triggers the lazy delegate which delivers the first value. I'm going to look in to that today :)

gpeal commented 6 years ago

This should be fixed now.