Hello folks, I am seeing a weird behaviour by Koin...
# koin
u
Hello folks, I am seeing a weird behaviour by Koin-Android Viewmodel. I have a main Activity with bottom navigation. The bottom navigation tabs
replaces
Fragments. I have created global instances of fragments in the activity (in order not to re-instantiate the fragments again on tab change). Now once a fragment is loaded and replaced (on tab change),its complete lifecycle is called (from
onAttach()
to
onDestroy()
and
onDetach()
). So I expected the viewmodel of the fragment to also get destroyed and
onCleared()
called once the
onDestroy()
of the fragment is called. Also new viewmodel should be instantiated when fragments is created again. But it is not happening as expected. The viewmodel is only created once and
onCleared()
is only called the first time
onDestroy()
of the fragment is called. I tested it using the following code :
Copy code
class HomeViewModel : ViewModel() {

    init {
        Log.d("Fragment_Checker","Viewmodel_INIT")
    }

    private var counter = 1


    fun getCounter():Int{
        counter++
        return counter
    }

    override fun onCleared() {
        Log.d("Fragment_Checker","ViewModel_Destroyed")
        super.onCleared()
    }
}

/*Fragment class */

class HomeFragment : androidx.fragment.app.Fragment() {

    val viewModel: HomeViewModel by viewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("Fragment_Checker","onCreate")
 
    }
    override fun onResume() {
        super.onResume()
        Log.d("Fragment_Checker","Counter "+viewModel.getCounter())
    }

    override fun onDetach() {
        super.onDetach()
        Log.d("Fragment_Checker","onDetach")
    }
    override fun onDestroy() {
        super.onDestroy()
        Log.d("Fragment_Checker","onDestroy")
    }
The log output looks like : onCreate Viewmodel_INIT Counter 2 //tab changed ViewModel_Destroyed onDestroy onDetach //move back to home tab onCreate Counter 3 //tab changed onDestroy onDetach
n
viewmodel is retained fragment and stores in activity, so it doesn't depend on separate fragment lifecycle, but depends on activity lifecycle. So
onCleared
will be called after
onDestroy
in activity https://developer.android.com/topic/libraries/architecture/viewmodel#lifecycle
u
Can you check the question again. I have added more explaination
from the link you gave : "ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes , while in the case of a fragment, when it's detached."
👍 2
o
If you are using global instances of fragments and not reinstantiating them each time, onDestroy of fragments shouldn't be called during replacements. (And similarly when you come back onCreate wouldn't be called) Others like onAttach, onCreateView, onDestroyView, onDetach would still be called, it's normal. If onDestroy is called on a fragment when you switch, then it seems you couldn't achieve what you intended(keeping global instances of fragments) Viewmodel, in this case, if attached to fragment lifecycle, will be destroyed if onDestroy of the fragment is called. However a question worths asking is this: Are you using the instances of same fragment class in these tabs or some of them? Because using same fragment class with same viewmodel class can mass things up as well.
u
no, I am not using same fragment class for any of the tabs. I have four tabs and four separate fragment class.
The thing which is baffling me the most is why viewmodel
onCleared()
is called only the first time I switch the tabs, never thereafter.
Also fragments
onCreate()
and
onDestroy()
are called everytime tab is switched.
o
Here it mentions a bug on framework for support library version 27.1.0. Can it be also your case? (Though you say it is called for one of them) https://stackoverflow.com/questions/49257197/oncleared-is-not-being-called-on-fragments-attached-viewmodel
u
I am using the latest androidx appcompat 1.1.0-alpha01 . So that can't be an issue i guess.