1

disclaimer, this is different question from my previous question

I am new in MVVM and I am little bit confused.

so If a user clicks the button in my fragment, then I will make a request to server to check if this user has created a music event or not, it he has not created a music event then move to Fragment B. here is my FragmentA

class FragmentA : Fragment() {

    lateinit var model: AViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        model = ViewModelProvider(this).get(AViewModel::class.java)


        button.setOnClickListener {
            model.checkIfUserHasCreatedEvent()
        }


        model.hasCreatedEvent.observe(this, Observer { hasCreatedEvent ->

            if (!hasCreatedEvent) {
                val chooseEventNameDestination = CreateEventFragmentDirections.actionToCreateEventName()
                findNavController().navigate(chooseEventNameDestination)
                model.navigationHasBeendHandled()
            }

        })



    }

}

and here is the viewmodel for this fragment

class AViewModel(application: Application) : AndroidViewModel(application) {

    val _hasCreatedEvent : MutableLiveData<Boolean> = UserClient.hasCreatedEvent
    val hasCreatedEvent : LiveData<Boolean>
       get() = _hasCreatedEvent

    fun checkIfUserHasCreatedEvent() {
        UserClient.checkIfUserHasCreatedAnEvent()

    }

    fun navigationHasBeendHandled() {
        _hasCreatedEvent.value = true // to reset data, to avoid the value to be false
    }


}

and here is the UserClient (I skip the repository for simplicity)

object UserClient {

    val hasCreatedEvent = MutableLiveData<Boolean>()

    fun checkIfUserHasCreatedAnEvent() {

        // perform networking to server ....
        // and post the value after getting the response

        hasCreatedEvent.postValue(result)

    }


}

when I first click the button, it works as expected, it moves from fragment A to fragment B. because after checking to the server, hasCreatedEvent == false.

the problem occurs when I back from fragment B to fragment A.

when get back from fragment B, the observer in fragment A is triggered more than once, even though I am not click the button, it is automatically triggered.

    model.hasCreatedEvent.observe(this, Observer { hasCreatedEvent ->

        // triggered 3 times in here 

        Log.d("AViewModel","result: $hasCreatedEvent")

        // result: true
        // result: false  <--- the problem
        // result: true

        if (!hasCreatedEvent) {
            // because there is a false value ...
            // then this block is triggered, and it makes it moves to fragmentB again
        }



    })

I believe the true value comes from navigationHasBeendHandled method from my viewModel, but I don't understand why there is false value again when I get back from fragment B to fragment A ? even though I don't click the button

I assume false value comes from UserClient.hasCreatedEvent that holds value after making request from server.

but I don't know how to solve this issue, because that false value makes it moves automatically to fragment B again.

java or kotlin are okay

Alexa289
  • 8,089
  • 10
  • 74
  • 178

2 Answers2

0

Because when you back to FragmentA, the viewModel been created again, and for java/kotlin initial value of Boolean is false. An easy solution is to create ViewModel for your Activity but not Fragments, this is what Google recommend, let the viewModel follow Activity's LifeCycle, and All fragments in this Activity will share this ViewModel.

Inso
  • 837
  • 1
  • 7
  • 11
  • I have tried to put log inside init block in my viewmodel, and it only triggered once when I first open the fragmentA, when I get back the init block is not called, it means the viewmodel is not destroyed – Alexa289 Mar 20 '20 at 05:55
  • @Alexa289 viewmodel will be cleared when fragment call onDestroy, not sure how you switch fragments, anyway, move viewmodel to Activity will solve this. – Inso Mar 20 '20 at 06:59
  • I am using Navigation component from android Architecture, so I use Single activity with many fragments as per the documentation – Alexa289 Mar 20 '20 at 07:01
0

You can remove observer like this after first time you observed it. You can try this:

model.hasCreatedEvent.observe(this, Observer { hasCreatedEvent ->

            if (!hasCreatedEvent) {
                val chooseEventNameDestination = CreateEventFragmentDirections.actionToCreateEventName()
                findNavController().navigate(chooseEventNameDestination)
                model.navigationHasBeendHandled()

                model.hasCreateEvent.removeObservers(this)
            }

        })
DB377
  • 403
  • 4
  • 11