There's a common application behavior pattern, when you can't go next unless current action is finished. A good example is authentication: once you provided the app with you login and password, and tapped "Sign In", the app will block for a while displaying you a sort of "Wait, I'm working" indicator. Even though this task is pretty common, I didn't manage to google a "typical" solution.
Major points I keep in mind:
There are absolutely no guarantees for Activity lifetime. Activities are guaranteed to be launched when user launches them, but then they can be killed at any moment. So, in general, Activities should be thought of as interaction points where your app and the user can discuss their "desires". It's always up to user to start this discussion.
On the other hand, there are Services, components which never talk to users directly. There are guarantees for Service lifetime, so it seems to be the right place to put your processing logic to.
So, for the task I described at the very beginning, it's fair to state that:
So, here's a question:
How do I properly make an Activity aware of which one of 4 modes should currently be active?
What I have considered:
Activity
+ AsyncTask
. Doesn't work at all as AsyncTask
is bound to specific Activity
instance and once Activity
is recreated (device orientation change is an example), AsyncTask
is bound to "wrong" context.
Activity
+ IntentService
. Activity triggers the service and provides the "request context" in Intent
. Once IntentService
is done, it uses sendBroadcast()
to tell the Activity
where we are. This doesn't work because by the moment IntentService
is done, Activity
can already be paused, so it won't receive the update.
Same as p.2, but using sendStickyBroadcast()
. This solves the missed updates problem, but Google says it's a bad practice because of some king of overhead or whatever.
Using IntentService
+ ContentProvider
+ Loader
. Activity triggers the service and provides the "request context" in Intent
. The request context has a magic "request token". This token describes a "unique intention to do something", so that when "something is done", it's possible to tell what it was and who wanted it. IntentService
starts processing by saving the request record to the database: namely, request token and status (started). Then it starts processing. Once processing is done, it updates the record status to "done" and puts a result there. At the same time, Activity
uses Loader
to listen to this record. It understands which mode it should run in, based on the status. This solution works perfectly for all scenarios including device orientation changes, leaving the activity, incoming calls, etc, but feels like a weird overkill.
I was wondering if there's an easier solution.
first of all, you are certainly on the "right direction" if you are taking in mind all the points you mentioned.
the problem you describing is very common, and concerns to most of applications
there is problem with some of your assumptions:
Activity + AsyncTask. Doesn't work at all as AsyncTask is bound to specific Activity instance and once Activity is recreated (device orientation change is an example), AsyncTask is bound to "wrong" context.
no one said AsyncTask
must been executed from an Activity
!!
it's also a good practice using AsyncTask
from android Service
derived class (not IntentService
..) . that's possible because Service
methods are executed from the main thread.
actually, that is the preferred solution to my believe.
Activity + IntentService. Activity triggers the service and provides the "request context" in Intent. Once IntentService is done, it uses sendBroadcast() to tell the Activity where we are. This doesn't work because by the moment IntentService is done, Activity can already be paused, so it won't receive the update.
if the activity already paused/destroyed - you don't have any reason to update it anyway!!!!!
instead, you can just strore this information persistently / static singeltone class, and when this activity resume - it will retreive it back, and display the relevant state.