Lifecycle-Aware components with Kotlin — Android Architecture Components
Every component introduced by Google is intended to be a solution to a bad/not good situation or a performance/code improvement. In this case, we want to discuss all problems that can come if we don’t use the lifecycle of the Android components properly.
Which are the problems?
- You are creating an app that plays video/music streaming from internet, you need the app to start buffering the media since it’s open, but playback until it is fully started. Probably you want to stop the video and buffering if the app is on the background and restart it when it comes up to the foreground. Finally, you need to cancel the playback and buffering when your app is closed and also release all the resources at this time.
- You were asked to develop an app that tracks the user’s location as soon as the user opens your app. Your app has to show the user’s location on the screen if it is on the foreground or to store it in the database if it is not on the foreground. Also, when the app is closed you have to stop tracking the user’s location and release all the resources.
- You have an app that requests and sends information to a server in the background to keep both synchronised. This flow of data should start right after the user opens the app, but we also want to know when the user sends the app to the background, closes it or performs any action on it. This synchronization has to be done at least every 5 minutes, and should be stopped when the app is closed.
Until now the way to handle this kind of situations is adding operations to the lifecycle callbacks of the dependent component (Activity, Fragment, Service, etc), but this approach ends up in a poor organization of code, it is difficult to maintain and it can generate a bunch of errors.
Most of the app components that are defined in the Android Framework have lifecycles attached to them. Lifecycles are managed by the operating system or the framework code running in your process. They are core to how Android works and your application must respect them. Not doing so may trigger memory leaks or even application crashes.
With the knowledge that we have until now, the normal way to handle the cases mentioned above is as follows:
AuditHelper.kt
This class is in charge to track any action done on the app, this includes when the app is started, paused and stopped.
MainActivity.kt
To report the requested actions we need to play with the lifecycle callback of the Activity like shown below.
This doesn’t look so bad, but in real apps we will end up with a lot of operation being executed on the callbacks and probably all of them are part of different components (class, service, etc) without any relationship between them. Also, it is completely your responsibility of execute the correspondent operation on the right callback so you release the resources when they are not need and avoid memory leaks or execute the right operation when a specific state is reached. It sounds very prone to errors, right? Well, LifeCycle-Aware components come to the rescue.
Lifecycle-Aware components
These components, officially released on January 22th, 2018, are intended to help handling in a more elegant way the operations that depend on the lifecycle. Lifecycle components react to changes on the lifecycle status of other components that are subscribed to observe, helping us to have better organized code, increasing the modularity, encapsulation and maintainability, and reducing the possibility to introduce errors or memory leaks.
Lifecycle-Aware components can be any of the following types:
LifecycleOwner:
An interface that represents a class that has Android lifecycle, like Activity, Fragment or Service. Also, it can be implemented in a custom class as we will see below.LifecycleObserver:
An interface that denotes a class that is observing any state change on theLifecycleOwner
it subscribes to observe. Also,LifecycleObserver
usesOnLifecycleEvent
annotation to subscribe its methods to observe specific component state change.
Let’s go to the code
We are going to refactor the examples we showed above to make them lifecycle aware.
Before we start, all the sample codes are written using kotlin, if you don’t know Kotlin or you want to learn more, I would like to invite you to visit this link and read my article about it. Also, if you want learn about Room, the Android Architecture Components for persistence, and simplify the way of how you interact with SQLite on your apps, I strongly recommend you to visit my article and learn more about this incredible component.
Ok, let’s see the code. The first thing we need to do is to update our gradle file. It should look like the following:
App.gradle
As we mention above, lifecycle aware components can be: LifecycleObserver or LifecycleOwner. Let’s start with our LifecycleObserver:
AuditHelperLifecycleAware.kt
Things to be noticed here:
- We need to implement the
LifecycleObserver
interface, this marks a class as a LifecycleObserver. It does not have any methods, instead, it relies onOnLifecycleEvent
annotated methods. - We use the annotation
@OnLifecycleEvent
to indicate that the method needs to be notified when a specific event occurs. For instance, we are indicating we want that the methodauditStated()
be executed each time theLifecycleOwner
, we subscribed to, goes to the stateSTARTED
and so on.
Now, let’s go the our LifecycleOwner
, in this case we are going to use an Activity which extends AppCompatActivity
that implements LifecycleOwner
interface.
MainActivityLifecycleAware.kt
Things to know:
- At the line 9, we are getting the lifecycle of the activity. Since
AppCompaqActivity
implementsLifecycleOwner
interface, we can get its lifecycle easier. activityLifecycle.addObserver(auditHelper!!)
method allows us to indicate we want ourAuditHelperLifecycleAware
instance to be notified of the state changes of this LifecycleOwner. The parameteraddObserver
method receives have to be a class that implementLifecycleObserver
interface.activityLifecycle.addObserver(auditHelper!!)
method allows us to indicate we want ourAuditHelperLifecycleAware
instance to be notified of the state changes of this LifecycleOwner. The parameter thataddObserver
method receives has to be a class that implementsLifecycleObserver
interface.
And that’s it, with a better organized code we are able to be aware of the changes of state of an Activity and react to this changes.
But hold on, that’s not all. What if I want to have my own LifecycleOwner? Don’t worry, you can do it without write tone of code. Lets see an example:
CustomLifecycleOwner.kt
Things to be noticed:
- Our custom lifecycleOwner has to implement the
LifecycleOwner
interface and implement the methodgetLifecycle()
as shown above. lifecycle.markState(state: State)
allow us to setup the current state of the class; triggering the lifecycle callbacks so the observers can react to the state changes.lifecycle.markState(state: State)
allow us to setup the current state of the class; triggering the lifecycle callbacks so the observers can react to the state changes.
And that’s all. We learned how to create lifecycle aware components, which is the difference between a LifecycleOwner and LifecycleObserver, how to use each of them and how implement our custom LifecycleObserver.
The whole code of the project can be gotten from here. Thanks for reading, if this article was useful or entertaining for you please clap it, share it and follow me. :)