Android Architecture Components: ProcessLifecycleOwner

Mert SIMSEK
Trendyol Tech
Published in
3 min readOct 18, 2017

How to know my app is in foreground/background? I see SO has a lot of question and answers about that. Actually I didn’t face any specific problem about doing something when your app is foreground or background, but I know lots of developer did. There are some naive workaround fixes that problem. But we can’t say “This is the best practice” in that case. Now android architecture saw that we need a hand here and solve that problem for us. (Again thanks to new components)

Recently I saw a tweet from Florina and I am suprized actually. They did the implementation for us again.

Only few days ago from this tweet, we talked about this in our team and everyone said their solution about the problem. What a coincidence, I saw this tweet and I really excited about reviewing source code of internal implementation.

Actually solution is pretty same with ours. Before dive into solution, I want to point out what we want to do.

  • When app is foreground, we want to be notified.
  • We don’t care about opening new activities. We just want to know app is in foreground or background.
  • If no activity left in the stack, this means it is not in foreground anymore.

I want to show sample first (how easy it is) and then show behind the scenes.

Sample

Let’s say we have 2 activities, ActivityA and ActivityB.

  • When user launches app, we will “create” and ‘start something’ depends on the case that checks if app is foreground.
  • When user start ActivityB from ActivityA, we don’t care about this. Because app is still visible to user.
  • When user press back from ActivityB to ActivityA, we don’t care about this. Because app is still visible.
  • When user press home button in any activity (A or B) we will “stop something”
  • When we come back from current running application to the our app. We don’t “create” but we will “start something” again. Because app is foreground now.

ForegroundBackgroundListener.kt

class ForegroundBackgroundListener : LifecycleObserver {

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun createSomething() {
Log.v("ProcessLog", "Lifecycle.Event.ON_CREATE")
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startSomething() {
Log.v("ProcessLog", "Lifecycle.Event.ON_START")
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopSomething() {
Log.v("ProcessLog", "Lifecycle.Event.ON_STOP")
}
}

ForegroundBackgroundApp.kt

class ForegroundBackgroundApp : Application() {

private lateinit var appObserver: ForegroundBackgroundListener

override fun onCreate() {
super.onCreate()

ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })

}
}

That is all! Yo don’t need to do anything else. This will meet all your needs to understand app is foreground or background.

You can also use other LifecycleEvent annotation like Lifecycle.Event.ON_RESUME, Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_DESTROY. These lifecycle will be called similar. But note that ON_DESTROY will never be invoked.

Lets see behind the scene

Behind the scene

ProcessLifecycleOwner is a LifecycleOwner. But implements its workaround inside it. And notify observers about process lifecycle changes.

public class ProcessLifecycleOwner implements LifecycleOwner {
@VisibleForTesting
static final long TIMEOUT_MS = 700; //mls

// ground truth counters
private int mStartedCounter = 0;
private int mResumedCounter = 0;
...
}

It creates a runnable which runs after a delay. Documentation explains better.

ON_PAUSE, ON_STOP, events will be dispatched with a delay after a last activity passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner won't send any events if activities are destroyed and recreated due to a configuration change.

So the delay period is 700ms, so as long as another activity is started and resumed after a current activity was paused and stopped within 700ms, the process has not undergone a lifecycle change, even though those individual activities did.

Counters are incremented and decremented by activity stack. we can easily get this information by hooking into the activity lifecycle events using Application.registerActivityLifecycleCallbacks.

Thanks to the team behind this architecture component.

Happy coding.

--

--