ToolmakerSteve ToolmakerSteve - 2 months ago 4
Android Question

Most reliable way to do ~200 ms work in Android onStop

I see frequent posts stating that file writing should be done in a background thread, even when the app is shutting down (

onStop
) -- even if the work is critical to the app.

I'm puzzled by this. Surely
onStop
is the one UI call where Android should, perhaps must, be lenient in giving the app time to complete critical work.

I am concerned that performing critical work on a background thread, does not inform the OS that the work is critical, and needs to be completed.

There are several related aspects to this:

----- What is bothering me; the reason I wrote this question -----


  1. Is it reliable to do critical work on a background thread, after allowing
    onStop
    to return?
    Doesn't the return of
    onStop
    signal to Android that the app has finished what is critical, and the app will function correctly when resumed even if android immediately kills it?



(In other words, seems to me the advice [to do that critical work in a background thread] is wrong. I'm trying to find evidence one way or the other. This is the why i wrote this question.)




----- Existence of any evidence that favors the background approach? -----


  1. Evidence that if I follow the advice, and do the work in a background thread, that Android takes the existence of that running thread into consideration, when deciding whether it is okay to kill the app. [If I were writing a mobile OS, I wouldn't give the existence of a background thread much weight. I suspect most complex apps have background threads still running.]

  2. Evidence that it is bad to delay the return from
    onStop
    by up to 200 ms.






----- Or existence of any evidence that it is okay to do it in the foregrround? -----


  1. Or conversely, evidence that doing it directly in the UI thread is okay up to some reasonable time, and evidence as to what time might be considered reasonable.






----- Or what do the big app writers do? -----


  1. Evidence about what approach is used by highly-downloaded, high-profile apps. Do they stay on UI thread while writing to file in onStop, or do that in the background? Or do they use a Service to be 100% sure? [I figure Android is unlikely to be changed in a way that will screw those guys over, unless absolutely necessary.]



NOTE: I've seen lots of opinions. I don't need to hear any more opinions. Looking for evidence.

NOTE: I'm not interested in hearing advice to create some Service or other solution that Android will keep running. I'm not talking about work that is lengthy enough to justify that. I'm talking about garden-variety work that every significant app does, when it is informed that it is being terminated.




UPDATE: I appreciate the information in the two responses so far, but I feel that one essential point is being overlooked:

There is one crucial difference between
onStop
and all the other UI callbacks:

When an app returns from onStop, the act of returning is a statement from the app to the OS that the app can now be safely killed. Right? Isn't that the essence of onStop?

Therefore, it logically follows that an app should not return from onStop until it has completed all critical work.

(And yes, one should obviously design the app such that this completion of critical work can be done as quickly as possible. But lets not lose the main point here. If you return, you are telling the OS it can now safely kill you. If it actually does kill you immediately, and your app state is messed up because you did that work on a background thread that isn't finished, then your approach is flawed. Isn't it? I'm trying to see what is wrong in my analysis here...)




UPDATE #2
In discussion with @CommonsWare (see comments under his answer), I have learned that an IntentService accomplishes what I want, and does not require any additional permissions to be asked from user.

I was thinking of iOS, which is very strict about background work. I believe any such scheme would require an additional app permission under iOS. I avoid additional app permissions, so as not to scare off any users.

So as an experienced iOS app developer, but a less-experienced Android developer, the answer I didn't know I needed was:


  1. Unlike iOS, IntentService can be used, WITHOUT ADDING ANOTHER APP PERMISSION, to do background work that the OS will continue, even after an app's activity has been terminated.



Because the IntentService will continue running, and is not expensive to start, and does not require an extra app permission, there is no "downside" to using IntentService to start background work, allowing onStop to return promptly, while ensuring that the critical work is done.

I have accepted CommonsWare's answer.

Answer

even when the app is shutting down (onStop)

onStop() is a method on Activity. It will be called when the activity is no longer visible. That may or may not have anything to do with whether the app is "shutting down". For example, transitioning from one activity to another triggers onStop(), as do configuration changes (by default).

Surely onStop is the one UI call where Android should, perhaps must, be lenient in giving the app time to complete critical work.

It is not a question of "leniency". onStop() is called on the main application thread. Anything you do on the main application thread ties up that thread, preventing Android from doing other work on that thread. Since the UI is driven by the main application thread, your UI will be frozen during the period of time you are tying up the main application thread in onStop().

Note that this is not unique to onStop(). Any place where you tie up the main application thread is a place where the UI is frozen. Android developers have adopted the term "jank" to specifically mean this behavior.

You may feel that 200ms of a frozen UI is perfectly acceptable. Other developers may not. Users may or may not.

But does that matter, during onStop? During onPause that would be bad, but what about onStop?

In many cases, it does. Just because the onStop() activity is no longer in the foreground does not mean that none of your activities are in the foreground, unless you only have one activity and this isn't a configuration change.

that Android takes the existence of that running thread into consideration, when deciding whether it is okay to kill the app

It doesn't, unless that thread is being managed by a Service (in which case, Android takes the Service into account, not a thread).

To turn the tables, I would be keenly interested in any evidence that you have that Android will terminate your process within ~200ms of onStop() being called. Otherwise, your thread will run to completion without issue.

I am specifically interested in the failure of the docs I've seen to discuss the different nature of onStop

That is because onStop() is not different, in the eyes of everyone else. You are welcome to believe that it is different, but please do not expect everyone else to "retcon" what has already been written about Android app development to adjust to your worldview.

Evidence that it is bad to delay the return from onStop by up to 200 ms.

"Bad" is a subjective description. What can be stated is:

  • onStop() is called on the main application thread (to prove this, log the thread IDs)

  • tying up the main application thread prevents other work from being done on that thread (fundamental to how threads operate)

  • Android aims to update the UI on a 60fps basis, or ~16ms/frame

  • ~200ms is ~12 frames at 60fps (long division)

When an app returns from onStop, the act of returning is a statement from the app to the OS that the app can now be safely killed.

An "app" does not return from onStop(). onStop() is a method on Activity. An app may have zero, one, or several activities. onStop() is loosely related to the application moving to the background, but onStop() will be called in other situations as well, as noted previously in this answer.

If you return, you are telling the OS it can now safely kill you

You are assuming that failing to return from onStop() would keep your process alive forever. onStop() is an advisory event, telling you "hey, your activity has moved to the background". How quickly you return from onStop() does not matter one iota to the OS process that is responsible for terminating processes to free up system RAM.

Comments