Lifecycle is released on Android X. Lifecycle 2.4.0 and the @onlifecycleEvent annotation has been deprecated. Lifecycleevening Server or DefaultLifecycleObserver are recommended instead

Lifecycle is ubiquitous in modern Android applications and it is the presence of various Lifecycle – Aware components that ensure the robustness of the application.

Lifecycle nature is a best practice for the Observer pattern. By implementing the LifecycleObserver interface, developers can customize Lifecycle – Aware components, Aware of LifecycleOwner lifecycle callbacks such as activities or fragments.

In the light of the new release, let’s review the use of the Lifecycle annotation and the alternatives to deprecating it

Lifecycle Events & States

Lifecyce defines Event and State using two sets of enums.

  • Events
    • ON_CREATE
    • ON_START
    • ON_RESUME
    • ON_PAUSE
    • ON_STOP
    • ON_DESTROY
    • ON_ANY
  • States
    • INITIALIZED
    • CREATED
    • STARTED
    • RESUMED
    • DESTROYED

Events correspond to the late-life callbacks of native system components such as activities, and each Event that occurs means that these LifecycleOwners enter a new State.

The LifecycleObserver as an observer can perceive events when the LifecycleOwner being observed changes its lifecycle State. LifecycleObserver can be defined in three ways:

  1. implementationLifecycleEventObserverinterface
  2. use@OnLifecycleEventannotations

Implement LifecycleEventObserver

public interface LifecycleEventObserver extends LifecycleObserver {
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
Copy the code

LifecycleEventObserver is a single-method interface that can be declared in Kotlin as a more succinctly written Lambda

val myEventObserver = LifecycleEventObserver { source, event ->
    when(event) {
        Lifecycle.Event.ON_CREATE -> TODO()
        Lifecycle.Event.ON_START -> TODO()
        else -> TODO()
    }
}
Copy the code

LifecycleEventObserver itself is a derivative of LifecycleObserver and will be used directly to addObserver into LivecycleOwner’s Lifecycle.

You need to write swich/case in onStateChanged to distribute the event yourself. Compared to methods like onCreate and onResume, which are used to rewriting activities or fragments, it is a bit wordy.

So Lifecycle gave us the @onlifecycleEvent annotation

Use the @onlifecycleEvent annotation

To use it, you simply inherit the LifecycleObserver interface and add annotations to the member methods

val myEventObserver = object : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onStart(a) {
        TODO()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreat(a) {
        TODO()
    }
}
Copy the code

After adding a registration, the Event distribution to LifecycleOwner automatically calls back the annotation matching member method, which developers love because it eliminates the manual switch/case process

Annotation parsing process

How is it that when an Event is distributed, it goes back to the annotation method?

LifecycleObserver added via addObserver is turned into a LifecycleEventObserver, and LifecycleOwner distributes the Event by calling its onStateChanged

Handle transformations in Lifecycline #lifecycleEventObserver

public class Lifecycling {
    
    @NonNull
    static LifecycleEventObserver lifecycleEventObserver(Object object) {
        boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
        boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
        // The observer is FullLifecycleObserver
        if (isLifecycleEventObserver && isFullLifecycleObserver) {
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
                    (LifecycleEventObserver) object);
        }

        // The observer is LifecycleEventObserver
        if (isFullLifecycleObserver) {
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
        }

        if (isLifecycleEventObserver) {
            return (LifecycleEventObserver) object;
        }

        finalClass<? > klass = object.getClass();int type = getObserverConstructorType(klass);

        // Observer is a class generated by apt
        if (type == GENERATED_CALLBACK) {
            List<Constructor<? extends GeneratedAdapter>> constructors =
                    sClassToAdapters.get(klass);
            if (constructors.size() == 1) {
                GeneratedAdapter generatedAdapter = createGeneratedAdapter(
                        constructors.get(0), object);
                return new SingleGeneratedAdapterObserver(generatedAdapter);
            }
            GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
            for (int i = 0; i < constructors.size(); i++) {
                adapters[i] = createGeneratedAdapter(constructors.get(i), object);
            }
            return new CompositeGeneratedAdaptersObserver(adapters);
        }
        
        // The observer needs to generate a wrapper through reflection
        return newReflectiveGenericLifecycleObserver(object); }...public static String getAdapterName(String className) {
        return className.replace("."."_") + "_LifecycleAdapter"; }}Copy the code

The logic is clear. There is no need to convert LifecycleEventObserver to different LifecycleObserver types.

Use a pseudocode to comb as follows:

if (lifecycleObserver is FullLifecycleObserver) {
  return FullLifecycleObserverAdapter // More on that later
} else if (lifecycleObserver is LifecycleEventObserver) {
  return this
} else if (type == GENERATED_CALLBACK) {
  return GeneratedAdaptersObserver
} else {// type == REFLECTIVE_CALLBACK
  return ReflectiveGenericLifecycleObserver
}
Copy the code

Annotations can be used in two ways.

Scenario 1: Use reflection to generate wrapper during Runtime

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    private final Object mWrapped;
    private final CallbackInfo mInfo;

    ReflectiveGenericLifecycleObserver(Object wrapped) {
        mWrapped = wrapped;
        mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Event event) { mInfo.invokeCallbacks(source, event, mWrapped); }}Copy the code

CallbackInfo is the key, collecting callback information for the current LifecycleObserver through reflection. OnStateChanged does not get an error because method is missing when called through reflection.

Scenario 2: Use APT to generate className + _LifecycleAdapter at compile time

In addition to utilizing reflection, Lifecycle also provides apt methods for handling annotations.

Add a Gradle dependency:

dependencies {
    / / Java
    annotationProcessor "Androidx. Lifecycle: lifecycle - compiler: 2.3.1." "
    / / kotlin writing
    kapt "Androidx. Lifecycle: lifecycle - compiler: 2.3.1." "
}
Copy the code

The compiler will then generate a class with the _LifecycleAdapter suffix based on the LifecyceObserver class name. For example, if we annotate onCreat and onStart, the generated code looks like this:

public class MyEventObserver_LifecycleAdapter implements GeneratedAdapter {
  final MyEventObserver mReceiver;

  MyEventObserver_LifecycleAdapter(MyEventObserver receiver) {
    this.mReceiver = receiver;
  }

  @Override
  public void callMethods(LifecycleOwner owner, Lifecycle.Event event, boolean onAny,
      MethodCallsLogger logger) {
    booleanhasLogger = logger ! =null;
    if (onAny) {
      return;
    }
    if (event == Lifecycle.Event.ON_CREATE) {
      if(! hasLogger || logger.approveCall("onCreate".1)) {
        mReceiver.onCreate();
      }
      return;
    }
    if (event == Lifecycle.Event.ON_START) {
      if(! hasLogger || logger.approveCall("onStart".1)) {
        mReceiver.onStart();
      }
      return; }}}Copy the code

Apt reduces the number of reflected calls, gives better performance, and of course sacrifices some compile speed.

Why use annotations

There are many types of events in the lifecycle, and we often do not need to implement them all. If we do not use annotations, we may need to implement all methods, resulting in extra useless code

The FullLifecycleObserver in the code above is an interface to all methods

interface FullLifecycleObserver extends LifecycleObserver {

    void onCreate(LifecycleOwner owner);

    void onStart(LifecycleOwner owner);

    void onResume(LifecycleOwner owner);

    void onPause(LifecycleOwner owner);

    void onStop(LifecycleOwner owner);

    void onDestroy(LifecycleOwner owner);
}
Copy the code

As we can see from the fact that the interface is not public (Java code), there is no intention for us to use such an interface, adding to the burden of developers.

Reasons for abandonment

If the notes are so good, why scrap them?

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

As you can see from the comments in the official documentation, annotations either rely on reflection to reduce runtime performance or APT to reduce compile speed, which is not a perfect solution.

We introduced annotations simply because we didn’t want to implement more than a few empty methods. Early Android projects do not support Java8 compilation, interface does not have the default method, now Java8 is the default configuration, you can add the default method to the interface, at this time annotations have lost the meaning of existence.

It is now officially recommended to use the DefaultLifecycleObserver interface to define your LifecycleObserver

public interface DefaultLifecycleObserver extends FullLifecycleObserver {

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {}@Override
    default void onStart(@NonNull LifecycleOwner owner) {}@Override
    default void onResume(@NonNull LifecycleOwner owner) {}@Override
    default void onPause(@NonNull LifecycleOwner owner) {}@Override
    default void onStop(@NonNull LifecycleOwner owner) {}@Override
    default void onDestroy(@NonNull LifecycleOwner owner) {}}Copy the code

FullLifecycleObserverAdapter, mindless callback FullLifecycleObserver can

class FullLifecycleObserverAdapter implements GenericLifecycleObserver {

    private final FullLifecycleObserver mObserver;

    FullLifecycleObserverAdapter(FullLifecycleObserver observer) {
        mObserver = observer;
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        switch (event) {
            case ON_CREATE:
                mObserver.onCreate(source);
                break;
            case ON_START:
                mObserver.onStart(source);
                break;
            case ON_RESUME:
                mObserver.onResume(source);
                break;
            case ON_PAUSE:
                mObserver.onPause(source);
                break;
            case ON_STOP:
                mObserver.onStop(source);
                break;
            case ON_DESTROY:
                mObserver.onDestroy(source);
                break;
            case ON_ANY:
                throw new IllegalArgumentException("ON_ANY must not been send by anybody"); }}}Copy the code

Note DefaultLifecycleObserver also can be used before the 2.4.0, exists in androidx. Lifecycle. The lifecycle – common – java8 this repository, 2.4.0 began to unified mobile androidx. Lifecycle. Lifecycle – common, has no java8 separate extension libraries.