Automatically Listen to All of Your Activity Lifecycle Event with ActivityLifecycleCallbacks | Part 1

Imagine how simple if you only need 1 class for globally log all of your Android Activity Lifecycle in the whole app

Farhan Yuda Pahlevi
5 min readJan 12, 2020
Photo by Chris Lawton on Unsplash (https://unsplash.com/photos/5IHz5WhosQE)

Hi guys, this is my new article about how to listening to Activity Lifecycle events. So, why I write this? Actually this is some task at my office, we need to log every activity lifecycle and send it to our analytics. At that time I’m not work on this but my colleague (2 person) do that. They finish it, code being reviewed, and we release it in production, but I just realize around 1 week a go that it cost too much for just only listening to the lifecycle event. Why? Our architecture forming as modular so for listening to the event they put some kind of base activity class in every module and all activity will extend base activity in each module, if we have 5 module then we need to create 5 base activity class (each module have 1) then manually extending 1 by 1 to that base class. Base class will be something like this :

abstract class BaseActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
log("onCreate()")
super.onCreate(savedInstanceState)
}

override fun onStart() {
log("onStart()")
super.onStart()
}

override fun onResume() {
log("onResume()")
super.onResume()
}

override fun onPause() {
log("onPause()")
super.onPause()
}

override fun onStop() {
log("onStop()")
super.onStop()
}

override fun onDestroy() {
log("onDestroy()")
super.onDestroy()
}

private fun log(lifecycle: String) {
Log.d("Lifecycle", "${this.javaClass.simpleName} $lifecycle in ${this.javaClass.`package`?.name}") // Then send to analytics
}
}

ActivityLifecycleCallbacks Comes as Saviour

At that point, I agree with the code which will send data to analytics every log called, but I feel a bit strange why it need base class in each module. Then, I’ll try to find some reference to the Android documentation and find something called ActivityLifecycleCallbacks, you can read here if you interest. Based on that, I know ActivityLifecycleCallbacks is some kind of interface provided by Application for listening to all of registered activity lifecycle event in your app. Noted that this only work on Android API level 14+ (above Ice Cream Sandwich). Here’s the interface :

public interface ActivityLifecycleCallbacks {
default void onActivityPreCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
}

void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState);

default void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
}

default void onActivityPreStarted(@NonNull Activity activity) {
}

void onActivityStarted(@NonNull Activity activity);

default void onActivityPostStarted(@NonNull Activity activity) {
}

default void onActivityPreResumed(@NonNull Activity activity) {
}

void onActivityResumed(@NonNull Activity activity);

default void onActivityPostResumed(@NonNull Activity activity) {
}

default void onActivityPrePaused(@NonNull Activity activity) {
}

void onActivityPaused(@NonNull Activity activity);

default void onActivityPostPaused(@NonNull Activity activity) {
}

default void onActivityPreStopped(@NonNull Activity activity) {
}

void onActivityStopped(@NonNull Activity activity);

default void onActivityPostStopped(@NonNull Activity activity) {
}

default void onActivityPreSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}

void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState);

default void onActivityPostSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}

default void onActivityPreDestroyed(@NonNull Activity activity) {
}

void onActivityDestroyed(@NonNull Activity activity);

default void onActivityPostDestroyed(@NonNull Activity activity) {
}
}

How to Implement ActivityLifecycleCallbacks?

First thing you need is Application class, ActivityLifecycleCallbacks need to be registered inside that. Just make Application class and register it to your manifest, then you need to make some listener for listening to the event. I make 2 sample for different case here. First if you only need to log, I think you can only make some object like this :

object ActivityLifecycleListener : Application.ActivityLifecycleCallbacks {
private const val TAG = "LifecycleCallbacks"
override fun onActivityPaused(p0: Activity) {
Log.d(TAG,"onActivityPaused at ${p0.localClassName}")
}

override fun onActivityStarted(p0: Activity) {
Log.d(TAG,"onActivityStarted at ${p0.localClassName}")
}

override fun onActivityDestroyed(p0: Activity) {
Log.d(TAG,"onActivityDestroyed at ${p0.localClassName}")
}

override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
Log.d(TAG,"onActivitySaveInstanceState at ${p0.localClassName}")
}

override fun onActivityStopped(p0: Activity) {
Log.d(TAG,"onActivityStopped at ${p0.localClassName}")
}

override fun onActivityCreated(p0: Activity, p1: Bundle?) {
Log.d(TAG,"onActivityCreated at ${p0.localClassName}")
}

override fun onActivityResumed(p0: Activity) {
Log.d(TAG,"onActivityResumed at ${p0.localClassName}")
}
}

Second, if you want to send analytics or make it advance you can make it not as object but as class so you can put other object inside it like if you need context or something else, here’s the code :

class ActivityLifecycleHandler(private val application: Application) :
Application.ActivityLifecycleCallbacks {
override fun onActivityPaused(p0: Activity) {
Log.d(TAG, "onActivityPaused at ${p0.localClassName}")
}

override fun onActivityStarted(p0: Activity) {
Log.d(TAG, "onActivityStarted at ${p0.localClassName}")
}

override fun onActivityDestroyed(p0: Activity) {
Log.d(TAG, "onActivityDestroyed at ${p0.localClassName}")
}

override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
Log.d(TAG, "onActivitySaveInstanceState at ${p0.localClassName}")
}

override fun onActivityStopped(p0: Activity) {
Log.d(TAG, "onActivityStopped at ${p0.localClassName}")
}

override fun onActivityCreated(p0: Activity, p1: Bundle?) {
Log.d(TAG, "onActivityCreated at ${p0.localClassName}")
}

override fun onActivityResumed(p0: Activity) {
Log.d(TAG, "onActivityResumed at ${p0.localClassName}")
}

companion object {
private const val TAG = "LifecycleCallbacks"
}
}

After that, you need to register to the application class like this :

class Application : Application() {
override fun onCreate() {
super.onCreate()
// This is for registering the listener object
registerActivityLifecycleCallbacks(ActivityLifecycleListener)
// This is for registering the listener class
// registerActivityLifecycleCallbacks(ActivityLifecycleHandler(this))
}
}

It’s work? Test it bro!

Great! You finish integrate it. Next step is open your device or emulator and run it. Start your logcat and put LifecycleCallbacks as filter. Voila you will find some kind of this log :

D/LifecycleCallbacks: onActivityCreated at MainActivity
D/LifecycleCallbacks: onActivityStarted at MainActivity
D/LifecycleCallbacks: onActivityResumed at MainActivity
D/LifecycleCallbacks: onActivityPaused at MainActivity
D/LifecycleCallbacks: onActivityCreated at SecondActivity
D/LifecycleCallbacks: onActivityStarted at SecondActivity
D/LifecycleCallbacks: onActivityResumed at SecondActivity
D/LifecycleCallbacks: onActivityStopped at MainActivity
D/LifecycleCallbacks: onActivitySaveInstanceState at MainActivity
D/LifecycleCallbacks: onActivityPaused at SecondActivity
D/LifecycleCallbacks: onActivityStarted at MainActivity
D/LifecycleCallbacks: onActivityResumed at MainActivity
D/LifecycleCallbacks: onActivityStopped at SecondActivity
D/LifecycleCallbacks: onActivityDestroyed at SecondActivity

Conclusion

This is only simple case which the goal of our task at my office is just sending the Lifecycle event to the analytics, for your information I’m not publishing codebase from my work but I only use similar usecase for logging the event. You can combined it with more advance way like integrate it with Dependency Injection or some kind of detect background and foreground globally. You can find sample code in my repository here :

That’s all from me, feel free to read and comment. I hope this article help your Android development. If you interest in flutter, you can read my article here in my medium.

--

--

Farhan Yuda Pahlevi
Farhan Yuda Pahlevi

Written by Farhan Yuda Pahlevi

Software Engineer | Senior Mobile Engineer at Gojek — Flutter - Android - iOS - KMM | Google Associate Android Developer 2017–2020 | http://pahlevikun.id

No responses yet