Get onPause & onResume like events at application/task level
Asked Answered
B

3

10

I was wondering what could be the reason for not having a callback at the application level when an application goes to background and comes to the foreground. Activity class's onPause and onResume are only called on the current top activity. If I want to stop some background task that has the application level scope, then there is no easy way I can stop it when the app goes to background. There is high demand for these event callbacks.

Why doesn't Android have a app level callback on pause and resume of applications? Can it be implemented in Android at the task(activity stack) level if not at app level?

The real problem :

A background Timertask refreshes UI with data from web at regular intervals. When app is no longer in foreground I want to stop it.

Currently I am putting the repeating code in a BaseActivity. This is at the activity level. The task stops and starts on each pause and resume of every activity and the event of app going to bg or coming to fg is hidden among one of these events, which I cannot know. I wanted to know if there is a better way of doing it, I mean knowing when the app has stopped being visible to the user.

Bethesde answered 7/9, 2011 at 18:5 Comment(2)
This is purely conjecture so I'm not going to put this as an answer, but I assume it has everything to do with how Android is designed. It's designed to go from Activity to Activity while the Application class itself is merely meant strictly as a global state setup that encompasses related activities. However, the activities are supposed to be designed as stand-alone so they can be used when needed from other apps.Perplexed
But can have a callback at the task level if not at the app level.Bethesde
H
4

Use Handler instead of TimerTask. A timed message for a Handler bound to an Activity's Looper will not be triggered if the activity is not active.

The pattern would be to send a timed message to the Handler which would in turn spawn a Thread/AsyncTask which would execute the request in the background and update the UI. A bit more overhead in thread creation/destruction but this is I/O bound anyway. You could make a thread pool if that overhead becomes a bototleneck (though I doubt it would).

If you really want to know when your application is no longer in the foreground, you can use the overlap in onStop/onResume between two activities. When going from A->B, B's onResume will be called before A's onStop. Therefore, you can increment a global counter in onResume and decrement it in onStop. That counter will become 0 if and only if no activities are visible. I used this successfully to track precise visits for analytics purposes. It does require a common base class for all your activities, though.

Hauptmann answered 16/9, 2011 at 21:53 Comment(5)
I want the task to run for whole app not for just one activity's life.Bethesde
"When going from A->B, B's onResume will be called before A's onStop." So I should check the counter for zero and stop the task in onStop of activity A. But its isn't the right way.Bethesde
That's the general idea, yes. In my case, I had to derive a base class for all my activities. Additionally, I had a singleton object ActivityVisibilityManager that had public static synchronized methods incrementCount, decrementCount, and isVisible. In the base class, I just called those.Hauptmann
Could have the count in Application object. Anyways still a better solution than the one Im using, performance wise. +50. Hope in future we get a callback from android, for such an event.Bethesde
This does not work if screen is rotating. Those calls are not overlapping.Buggy
K
3

Are you talking about android.app.Application class? There's single Application created when your app starts, before starting some Activity or Service, and it lives as long as your app remains in memory.

You may extend this Application and put there some global data. Specify in manifest in <application android:name=".YourApp"> the name of your extended class.

Now you should understand, that Application as such doesn't go to foreground or background, only Activity can. However, from your Activity, you can call getApplication to get your single Application instance (use casting), and call your own methods related to focus change, thus knowing if your app as a whole is in foreground or background, and behave as needed.

And Service has also getApplication() method, which receives same Application object.

Most developers probably don't realise that they can have single Application object keeping needed app data, not only bunch of Activities and Services.

Ketron answered 16/9, 2011 at 20:54 Comment(4)
Thats pretty much how I am handling it now. I am putting the repeating code in a BaseActivity. This is at the activity level. The task stops and starts on each pause and resume of every activity and the event of app going to bg or coming to fg happens on one of these events, which I cannot know. I wanted to know if there is a better way of doing it, I mean knowing when the app has stopped being visible to the user.Bethesde
Your app has stopped being visible to the user when any of its Activity goes to background (onPause called).Ketron
A call to onPause means your activity is going to background, and does not always mean app is going to bg. onPause of current activity is called even when a new activity is launched, that does not mean your app has gone to bg. Your point in answer - "Application as such doesn't go to foreground or background, only Activity can" I need to know when a app goes to bg, like when home button is pressed, or when a new app is launched by tapping on notifications.Bethesde
Try using Activity.onUserLeaveHintKetron
T
0

If you want to do some background task that has application level scope then you should be launching a new thread on a Service to do this task for you.

The Service is independent from any Activity and so will continue to run your task thread until you stop the it.

Tiffaneytiffani answered 7/9, 2011 at 18:25 Comment(4)
Yes, one current way to solve his problem is to create a Service and then use the individual Activity's onPause() and onResume() to keep track of when your App is in the foreground and then stopService() when it is not. But I think his question is why it takes so much boilerplate just to make this fairly common pattern work.Aemia
@Joel F: Yes. Exactly. I can do the stopping and starting the task even without a service, but have to do the same at every onPause and onResume of every activity in the app.Bethesde
I think I understand what you mean now. You want to be able to stop your task when your app is no longer in the foreground? May I ask what kind of work the task is? Must it stop as soon as the app is no longer in the foreground?Tiffaneytiffani
It refreshes UI with data from web at regular intervals. When app is no longer in foreground I want to stop it.Bethesde

© 2022 - 2024 — McMap. All rights reserved.