One of the many good things that google has brought into android world; is Architecture Components and then followed by Android Jetpack. Those has made the life of developers more organized and testable.
Everyone of us as Android Developer must have seen the case where they should execute some piece of code in specific lifecycle event (onCreate(), onResume(), .... etc); for example registering callbacks at onResume() and unregister them at onPause() because if you forgot to unregister you may end up in memory leak issues or even some runtime crashes. Moreover, Your code may get ugly by time as you may need to do some logic in a specific lifecycle event.
What about context(application or activity) references that you may use in another class you need for a particular purpose. you must provide a mechanism for getting rid of that reference so it can be collected by garbage collector if needed and avoid memory leaks. Sometimes to do that you'll end up doing many things in specific lifecycle event and with another classes and code to do at the same event, the code will get uglier. Here comes the lifecycle component to save your day.
Lifecycle component provides us with an easy way to make your mind and code more organized and decouples your code. Let's start with a simple example:
class SimpleInteraction(private var listener: InteractionCallback? = null) {
private var TAG = "SimpleInteraction"
private var isListening = false
private fun unregisterCallback() {
listener = null
}
fun startListening() {
isListening = true
}
fun stopListening() {
isListening = false
unregisterCallback()
}
fun doingSomeAction() {
Log.d(TAG, "Action happened, call the interaction callback")
if (isListening) {
listener?.onInteraction()
}
}
interface InteractionCallback {
fun onInteraction()
}
}
In this example you are using this class to call the listener to interact with the action happened. Ok, let's say that this Callback is implemented by an Activity, first you will need to instantiate the SimpleInteraction class in your activity and pass (this) as it is InteractionCallback and then in onResume() you need to call startListening() and in onPause() you'll call stopListening(), well it seems like alot to ask just to use this class.
Using Lifecycle Arch Component makes your life a lot easier and your code more organized. Ok let's see how to use it.
First things first, you need to add this dependency in your build.gradle(app) and sync your project:
def lifecycle_version = "2.0.0"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
and if you’re not using AndroidX include this dependency instead
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
And if you’re not using AndroidX include this dependency instead:
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
Then, make SimpleInteraction class implement the interface LifecycleObserver.
Here is the good part, the function you want to invoke at onResume() mark it with this annotation:
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
And the function you want to invoke at onPause() mark it with:
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
And that's all, now you can guarantee that those functions will be invoked at those events. there is only one thing that’s still left to do, add your LifecycleObserver to a LifecycleOwner (activity for example):
activity.lifecycle.addObserver(simpleInteractionObject)
In my example I passed the lifecycle owner to my class to make things simpler and organized:
class SimpleInteraction(lifecycleOwner: LifecycleOwner, private var listener: InteractionCallback? = null) : LifecycleObserver {
init {
lifecycleOwner.lifecycle.addObserver(this)
}
private var TAG = "SimpleInteraction"
private var isListening = false
private fun unregisterCallback() {
listener = null
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun startListening() {
isListening = true
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun stopListening() {
isListening = false
unregisterCallback()
}
fun doingSomeAction() {
Log.d(TAG, "Action happened, call the interaction callback")
if (isListening) {
listener?.onInteraction()
}
}
interface InteractionCallback {
fun onInteraction()
}
}
LifecycleOwner is an Interface that is implemented by the class that owns or holds and run through a known lifecycle, like Activities and Fragments. they implement this interface to publish their state to observer like our own in the example above.
You can make your own LifecycleOwner class, let's take and example,let's say you don't like the android navigationframework and you have decided to use another navigation framework to satisfy your needs. let's say you choseConductor Framework, you can check it at Github or even you want to create your own navigation system.
You have a Controller class which is in control of the view just like the Fragment and have its own lifecycle. In this case, how can you make your SimpleInteraction Class listen to the controller lifecycle, knowing that Controller doesn't implement LifecycleOwner Interface by default.
To publish the events of the Controller so that you can register your observer to listen to them, you need to implement LifecycleOwner Interface in your Controller:
class ChatController(args: Bundle) : Controller(args), LifecycleOwner
And then you should instantiate a LifecycleRegistery object in your controller:
mLifecycleRegistry = LifecycleRegistry(this)
Then you must implement the interface function:
getLifecycle()
And return LifecycleRegistery:
override fun getLifecycle(): Lifecycle {
return mLifecycleRegistry
}
All you have left to do is to publish your controller's lifecycle events just like that:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
mLifecycleRegistry = LifecycleRegistry(this)
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
And so on for other lifecycle events. And that's it, you made your Controller a LifecycleOwner and you can observe these events in any class.