65

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.

Sever
  • 2,338
  • 5
  • 35
  • 55
  • Did you find a solution for the back issue? I have the same issue with the solution suggested by google. Wonder if I misunderstood what they said and actually updating the toolbar should not be happening in there and it should be tied to a fragment lifecycle instead. – Alex Jan 07 '22 at 20:33

5 Answers5

52

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()
    }
}
Top-Master
  • 7,611
  • 5
  • 39
  • 71
Embydextrous
  • 1,611
  • 1
  • 12
  • 20
  • 5
    Unlike normal `onActivityCreated()` that is called after `onViewCreated()`, the `onCreated()` method is called before `onCreateView()` – Misagh Emamverdi Jul 17 '21 at 16:23
  • 2
    d= (◕‿↼ ) Too bad! The `@OnLifecycleEvent` notation is deprecated nowadays as well, and docs suggest to use `DefaultLifecycleObserver` or `LifecycleEventObserver` instead. – Top-Master May 05 '22 at 16:58
  • 3
    (Someone tell Google to deside once forever, and not just write whatever, without any standard.) – Top-Master May 05 '22 at 17:01
19

All I needed was onActivityCreated(...), hence I did implement an observer that:

  • Automatically removes itself (using .removeObserver(...)).
  • Then calls passed callback (update()).

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()
})

But to support older Android API levels, either your Activity needs to be of androidx's AppCompatActivity type (which has getLifecycle()), or, use a simple @SuppressWarnings("deprecation").

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Sever
  • 2,338
  • 5
  • 35
  • 55
  • 2
    https://developer.android.com/reference/androidx/lifecycle/DefaultLifecycleObserver#onCreate(androidx.lifecycle.LifecycleOwner) - This method will be called after the LifecycleOwner's onCreate method returns. – Sever Jun 08 '22 at 10:18
  • Do I understand correctly that, if I make a multi-triggering callback solution (f.e. onResume - this state can be called more than 1 time within a lifecycle), then the callback will work only once, because after the first triggering, it will be unsubscribed? Maybe, better is to make unsubscription in the latest lifecycle callback 'onDestroy'? – neronovs Sep 09 '22 at 11:22
9

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

oaosj
  • 91
  • 2
7

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

AndroidEngineX
  • 975
  • 1
  • 9
  • 22
1

onActivityCreated is deprecated in API level 28.

use onViewCreated for code touching the view created by onCreateView and onCreate for other initialization. To get a callback specifically when a Fragment activity's onCreate is called, register a androidx.lifecycle.LifecycleObserver on the Activity's Lifecycle in onAttach, removing it when it receives the CREATED callback.

The annotation @OnLifecycleEvent is deprecated too.

This annotation required the usage of code generation or reflection, which should be avoided. Use DefaultLifecycleObserver or LifecycleEventObserver instead.

The simplest solution: In general, in most cases the onActivityCreated issue can be resolved by moving the code to onViewCreated. If that doesn't work for you, continue reading down.

====================================================================

So, to fix the issue with the deprecated onActivityCreated and OnLifecycleEvent annotation you should do the following:

  1. Implement DefaultLifecycleObserver.
  2. Register your class as observer in onAttach().
  3. Override onCreate(owner: LifecycleOwner) and move your code from onActivityCreated in it.
  4. De-register the observer when the CREATE event is received in onCreate()

See Kotlin and Java examples below:

Kotlin:

class YourFragment : Fragment(), DefaultLifecycleObserver {

    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Register your class as observer
        activity?.lifecycle?.addObserver(this)
    }

    override fun onCreate(owner: LifecycleOwner) {
        super<DefaultLifecycleObserver>.onCreate(owner)
        // Remove the observer
        activity?.lifecycle?.removeObserver(this)

        //Move here your code from onActivityCreated(savedInstanceState: Bundle?) 

    }

}

Java:

public class YourFragment extends Fragment implements DefaultLifecycleObserver {

    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        // Register your class as observer
        if (getActivity() != null) {
            getActivity().getLifecycle().addObserver(this);
        }
    }

    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onCreate(owner);
        // Remove the observer
        if (getActivity() != null) {
            getActivity().getLifecycle().removeObserver(this);
        }

        //Move here your code from onActivityCreated(savedInstanceState: Bundle?) 

    }

IMPORTANT: Note that onActivityCreated is called after onCreateView, but DefaultLifecycleObserver.onCreate is called before onCreateView. So, if until now you were using in onActivityCreated something initialised in onCreateView, you'll have to move it somewhere else. E.g. in onViewCreated().

Ivo Stoyanov
  • 16,256
  • 8
  • 62
  • 65