onActivityCreated is deprecated, how to properly use LifecycleObserver?

AndroidAndroid FragmentsAndroid ActivityAndroid Lifecycle

Android Problem Overview


Google deprecate fragment’s onActivityCreated() on Android and recommend to use LifeCycleObserver:

 To get a callback specifically when a Fragment activity's
     * {@link Activity#onCreate(Bundle)} is called, register a
     * {@link androidx.lifecycle.LifecycleObserver} on the Activity's
     * {@link Lifecycle} in {@link #onAttach(Context)}, removing it when it receives the
     * {@link Lifecycle.State#CREATED} callback.

So I try to make it in recommended way, but only state I can observe in Logcat is just State: INITIALIZED.

 private lateinit var lifecycleObserver: LifecycleObserver

 override fun onAttach(context: Context) {
    super.onAttach(context)

    hostActivity = context as HostActivity

    lifecycleObserver = object : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun onCreate() {
            Logger.tag("SOME-TAG")d("State: ${lifecycle.currentState}")
            
            if(lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
                Logger.tag("SOME-TAG").d("CREATED")
                hostActivity.lifecycle.removeObserver(lifecycleObserver)
            }
        }
    }

    hostActivity.lifecycle.addObserver(lifecycleObserver)
}

What is wrong in code above?

UPDATE 1: Looks like I forgot to use hostActivity.lifecycle.currentState and checked fragment's lifecycle instead of Activities lifecycle.

UPDATE 2: Suggested by Google approach not worked for 1 Host activity and 2 fragments when you click back button from one to another, cause onAttach never called, but onActivityCreated called.

Android Solutions


Solution 1 - Android

As per the changelog here

> The onActivityCreated() method is now deprecated. Code touching the > fragment's view should be done in onViewCreated() (which is called > immediately before onActivityCreated()) and other initialization code > should be in onCreate(). To receive a callback specifically when the > activity's onCreate() is complete, a LifeCycleObserver should be > registered on the activity's Lifecycle in onAttach(), and removed once > the onCreate() callback is received.

You can do something like this in your fragment class:

class MyFragment : Fragment(), LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreated() {
        // ... Your Logic goes here ...
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        activity?.lifecycle?.addObserver(this)
    }

    override fun onDetach() {
        activity?.lifecycle?.removeObserver(this)
        super.onDetach()
    }
}

Solution 2 - Android

I did it in next way:

class MyActivityObserver(
    private val update: () -> Unit
) : DefaultLifecycleObserver {

    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        owner.lifecycle.removeObserver(this)
        update()
    }
}

and use it in fragments onAttach (or another lifecycle method) like:

myActivity.lifecycle.addObserver(MyActivityObserver {
    myOnActivityCreated()
})

Solution 3 - Android

You can consider the Lifecycle.State as the nodes in a graph and Lifecycle.Event as the edges between these nodes.

So you will never reached the State.Created on your ON_CREATE function.

Solution

class YourFragment : Fragment(), LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onCreated(){
        Log.i("tag","reached the State.Created")
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        lifecycle.addObserver(this)
    }

    override fun onDetach() {
        super.onDetach()
        lifecycle.removeObserver(this)
    }
}

For more details

https://developer.android.com/topic/libraries/architecture/lifecycle#lc

Solution 4 - Android

The best way to solve the issue is to use lifecycleScope which is present in the activity lifecycle. Below is the code snippet

override fun onAttach(context: Context) {
    super.onAttach(context)
    activity?.lifecycleScope?.launchWhenCreated {
        setupActionbar()
    }
}

How does it work? launchWhenXxx runs the launch block when it automatically reaches the specified state(in this case it is Created) and if the lifecycle goes to the destroyed state it cancels the launched coroutine automatically. Internally lifecycleScope uses Dispatchers.Main.immediate and hence there is no penalty of thread switching

Pros of this approach are following:

  1. You don't have to manually maintain registering and deregistering of the observer
  2. No need to overwrite two lifecycle methods

You have to latest activity and fragment dependencies to use lifecycleScope attached to the lifecycle

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSeverView Question on Stackoverflow
Solution 1 - AndroidEmbydextrousView Answer on Stackoverflow
Solution 2 - AndroidSeverView Answer on Stackoverflow
Solution 3 - AndroidoaosjView Answer on Stackoverflow
Solution 4 - AndroidAndroidEngineXView Answer on Stackoverflow