📜 ⬆️ ⬇️

Android Lifecycle-aware Architecture Components



November 6, 2017, Google has published information about the announcement of a stable version
architectural components . Google developers provided an application architecture guide and introduced a number of classes and interfaces that simplify building applications with built architecture, ease new programmers from joining the project, and reduce the threshold for entry into the world of adult development for people who have just started programming for Android.

The presented components for working with the life cycle of Android can be compared with a clockwork hidden from the eyes. Just a couple of lines of code and everything works. But how does everything work? And in general, is it worth using architectural components in your home projects or even in projects with hundreds of thousands of active installations?

Disclaimer
Developer code is provided in the Kotlin development language. Excerpts from Google’s source code are provided in Java. In the excerpts of the code may be omitted.

Lifecycle, lifecycle-aware components and activities


The life cycle is a very important point in the world of android development, which is often not given enough attention. For this reason, users may experience errors in the application. For example, during a phone call, the application may terminate with a critical error. This is due to the re-creation of activations and unprocessed state preservation.
')
Part of the problem of rebuilding activit can be avoided. For example, to prohibit the re-creation - put in the manifest the activation setting android: screenOrientation = “portrait” . But this will only solve problems with the re-creation of activations during configuration changes (for example, changing the orientation of the screen). The problem that at some point the operating system does not have enough memory and it will destroy the process with executable activation, this method does not solve. Returning to working with the application, the first thing that the user sees is a critical error.

One way or another, the developer needs to take care of handling the life cycle states. Lifecycle-aware components come to the rescue. The architectural components have a stable version 1.0 and can be used in the production-development of applications.

Pros and cons of using lifecycle-aware components


Consider the practical advantages and disadvantages of using components.

Plus certainly more

  1. Connecting a new employee to the application development team. All android developers know and know how to use official libraries from Google. No need to spend time learning local solutions to maintain the architecture;
  2. less code when developing features;
  3. component stability;
  4. improving the stability of the application after the introduction of components.

Minuses

  1. time to familiarize with the components and adding to the project;
  2. code was added to support the architecture when developing a new function, but this minus is easily solved by generating code. Good articles on this topic here and here .

How to work with lifecycle-aware components?


Starting with the Support Library version 26.1.0, fragments and activations out of the box implement the LifecycleOwner interface. This interface has only one method - getLifecycle () .
To add a life cycle event observer, all you need is to implement the LifecycleObserver interface in the class observer and write it in the activation / fragment

private fun addLifecycleObserver() { lifecycle.addObserver(observer) } 

And all? Yes, for a developer, this is where the work ends. It is enough to mark the necessary methods with annotations in the observer code and react to life cycle events.

 @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun init(){} 

An interesting fact is that with the same annotation you can mark several methods and all of them will be called when the state of the life cycle changes.

What is behind the pair of lines, how does everything work, what are the nuances?
Let's find the answers to the questions listed below on the example of the fragment.

What does the fragment return by implementing the LifecycleOwner interface in the getLifecycle () method? Description of the main methods


The fragment implements the LifecycleOwner interface, implementing the getLifecycle () method : Lifecycle .

Lifecycle is an abstract class that defines an object as an object that has an Android life cycle.

Implementing this class LifecycleRegistry takes over all the work of monitoring the addition, removal of observers, handling life cycle events, reporting life cycle changes to all observers.

Adding an observer.

 @MainThread public abstract void addObserver(@NonNull LifecycleObserver observer); 

An important nuance is that when LifecycleObserver is added to the list of observers, the observer will receive events about the change of all the states that precede the current one.

That is, if LifecycleOwner is in the Lifecycle.State.STARTED state when adding LifecycleObserver, the latter will receive two Lifecycle.Event.ON_CREATE and Lifecycle.Event.ON_START events.

So, we have a guarantee that our observer will go through all the steps of initialization, relying on life cycle events, and will not miss any configuration stage.

Removing an observer from the list of observers occurs in the method.

 @MainThread public abstract void removeObserver(@NonNull LifecycleObserver observer); 

If the observer is removed during a life cycle state change and the sending of a state change event is triggered after deletion, the observer will not receive this event.

If the observer has several methods waiting for one event and at least one of the methods was called when the observer was removed from the list of observers, then all other methods will also be called and only after that the deletion will occur.

Return current status on request.

 @MainThread public abstract State getCurrentState(); 

At any time, you can query the current state of the life cycle and, based on the answer, take any action. The method will return an instance of the State enumeration.

There are the following types of State

INITIALIZED - this state corresponds to the time when the entity implementing the LifecycleOwner interface was created, but the onCreate () method was not called anymore.

CREATED - this state is active after calling the onCreate () method and before calling onStop ().

STARTED - this state is active after calling the onStart () method and before calling onPause ().

RESUMED - this state occurs after calling the onResume () method.

DESTROYED - this state occurs immediately before the onDestroy () call. When this state occurs, LifecycleOwner no longer sends state change events.

What happens when you add an observer to the watch list?


 @Override public void addObserver(@NonNull LifecycleObserver observer) { State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED; ObserverWithState statefulObserver = new ObserverWithState(observer, initialState); <...> } 

When the lifecycle.addObserver (observer) method is called, the observer is placed in the instance constructor of the wrapper class ObserverWithState. As is clear from the class name, this class stores observer with the last processed life cycle state. Initially sets the status to DESTROYED or INITIALIZED.

 @Override public void addObserver(@NonNull LifecycleObserver observer) { <...> ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); if (previous != null) { return; } LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); if (lifecycleOwner == null) { // it is null we should be destroyed. Fallback quickly return; } <...> } 

After creating an instance of the observer with the last processed state of the life cycle - we try to add an observer to the FastSafeIterableMap collection using the putIfAbsent () method.

 @Override public V putIfAbsent(@NonNull K key, @NonNull V v) { Entry<K, V> current = get(key); if (current != null) { return current.mValue; } mHashMap.put(key, put(key, v)); return null; } 

If the method returns an element, then it already exists in the collection and you do not need to add it again. What happens next in the code. The addObserver () method stops if there is an existing observer in the list. Also, work is terminated if lifecycleOwner == null .

 @Override public void addObserver(@NonNull LifecycleObserver observer) { <...> State targetState = calculateTargetState(observer); mAddingObserverCounter++; while ((statefulObserver.mState.compareTo(targetState) < 0 && mObserverMap.contains(observer))) { pushParentState(statefulObserver.mState); statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState)); popParentState(); // mState / subling may have been changed recalculate targetState = calculateTargetState(observer); } <...> } 

The current state of the life cycle is calculated and events begin to be sent until the state stored in the observer is less than the current one.

What is upEvent (state: State)? Note also that there is a downEvent (state: State). Depending on what is happening now with the life cycle, based on the current state, you can determine which event should be sent to the observer.

It is easy to deal with this by looking at the body of the methods and the diagram below.



 private static Event downEvent(State state) { switch (state) { case INITIALIZED: throw new IllegalArgumentException(); case CREATED: return ON_DESTROY; case STARTED: return ON_STOP; case RESUMED: return ON_PAUSE; case DESTROYED: throw new IllegalArgumentException(); } throw new IllegalArgumentException("Unexpected state value " + state); } private static Event upEvent(State state) { switch (state) { case INITIALIZED: case DESTROYED: return ON_CREATE; case CREATED: return ON_START; case STARTED: return ON_RESUME; case RESUMED: throw new IllegalArgumentException(); } throw new IllegalArgumentException("Unexpected state value " + state); } 

How does LifecycleOwner report to LifecycleObserver about events occurring in a fragment's life cycle?


The snippet that implements the LifecycleOwner interface contains a number of methods available to call that correspond to lifecycle events: such as performCreate (savedInstanceState: Bundle) , performStart () , performStop (), and others.

The FragmentManagerImpl class calls these methods, and the corresponding onStart, onStop, and other methods are called in the fragment in turn. And also the methods of the LifecycleRegistry class are called.

 void performStart() { <...> onStart(); mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); } 

In the LifecycleRegistry class, the state is calculated, about which the next event should be sent based on the received event.

 public void handleLifecycleEvent(@NonNull Lifecycle.Event event) { State next = getStateAfter(event); moveToState(next); } 

And after that, it is calculated what type of event should be sent to the observer - upEvent (state: State) or downEvent (state: State)

 void dispatchEvent(LifecycleOwner owner, Event event) { State newState = getStateAfter(event); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; } 

Conclusion


In fact, only some of the classes and interfaces created by Google are described. But for the presentation of how everything happens and what lies behind a couple of lines of code this is enough.
Google developers have provided a truly powerful tool for developing applications with supporting architecture. In conjunction with other components, the developer has the opportunity to develop reliable applications and not to write their own, not always ideal solutions.

Source: https://habr.com/ru/post/353052/


All Articles