androidandroid-lifecycleandroid-jetpackandroid-viewmodelandroid-configchanges

Android How Lifecycle-Aware Components Detect Configuration Change inside ViewModel


My Fragment:

class FirstFragment : Fragment() {
    private lateinit var binding: FragmentFirstBinding
    private lateinit var viewModelFactory: FirstViewModelFactory
    private lateinit var viewModel: FirstViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_first, container, false)
        viewModelFactory = FirstViewModelFactory(requireActivity().application, this.lifecycle) //<- Lifecycle object
        viewModel = ViewModelProvider(this, viewModelFactory).get(FirstViewModel::class.java)

        return binding.root
    }
}

My ViewModel:

class FirstViewModel(application: Application, lifecycle: Lifecycle) : AndroidViewModel(application), LifecycleObserver {
    init {
        lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private fun showOnStopMessage() {
        Log.v("xxx", "onStop called!!")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private fun showOnStartMessage() {
        Log.v("xxx", "onStart called!!")
    }
}

The above setup works well in no-configuration-change environment, showOnStopMessage() gets called when app goes to the background, and showOnStartMessage() gets called when the app is brought back to the foreground.

The problem is, when configuration-change happens (like rotating the screen), those functions are not being called any more.

Why this happens? How to detect and "survive" configuration-change? Thanks in advance.


Solution

  • As far as I understand, the problem is that your ViewModel is created only once (as it should be) and it only adds the lifecycle of the first fragment as a LifecycleObserver. When you rotate the screen, the same ViewModel is returned and it'll still try to react to the changes of the old Fragment, which won't happen.

    I'd suggest not dealing with lifecycle inside the ViewModel at all (remove the related code from the Factory and from the ViewModel). Just call:

    lifecycle.addObserver(viewModel)
    

    right after the ViewModel is obtained, inside onCreateView.