Using a BroadcastReceiver to launch an AsyncTask - android

I'm trying to update the state of a UI on receipt of a push notification. In order to do this, I need to start an AsyncTask that performs some network operations and then updates the UI based on the result.
According to the documentation for BroadcastReceiver, performing asynchronous operations within a receiver is unsafe because the process executing it may be killed as soon as onReceive() returns, assuming there are no other "application components" in that process.
Is the BroadcastReceiver running in its own process, or in the same process as the containing Activity? Since I only care about the completion of the task as long as there is a UI to update, I'm not worried about the AsyncTask dying if the activity is closed. Assuming the BroadcastReceiver is in the same process as the activity, does this make it okay/safe to launch the task I've described from within the receiver?
Edit:
To clarify, I am registering the receiver in the activity's onResume() and unregistering it onPause(), so it should only be receiving intents when the activity is already active.

Broadcast receiver is not running on it's own process, it's running on UI thread.
Your process will be killed after onReceive method returns only if there is no other activity or service in your app is running.
If your broadcast receiver is an instance of an inner class and only receive when your activity is active, then your process will not be killed after onReceive method returns.

If inside your AsyncTask, you need a context, then I think a service is better. If not, there is no problem using AsyncTask.

Before Honeycomb (API11), you had to use a service.
Since Honeycomb (API11), you can use goAsync() :
This can be called by an application in onReceive(Context, Intent) to
allow it to keep the broadcast active after returning from that
function. This does not change the expectation of being relatively
responsive to the broadcast (finishing it within 10s), but does allow
the implementation to move work related to it over to another thread
to avoid glitching the main UI thread due to disk IO.

What I would recommend doing is startActivity(intent) from the broadcast receiver. Thats all. Inside the intent I would provide the event information you speak of, you can just set a parameter in the bundle. You can then examine this inside the Activity onStart() or onCreate() whichever gets called. If the flag is there, then from the Activity kick off the AsyncTask.
No need to use a service at all, with all the binding and communication limitations from service-activity.
Remember you can also startActivityForResult() as well. I think that you don't want to do anything except pass and forward inside a broadcast receiver.
BTW, Activities don't need to have UI's. There can be faceless activities.

Related

UI update without using Broadcast Receiver or Handler from Service in android

I know service is running on main thread so why are we using Broadcast Receiver or Handler to update UI in android. can we directly update UI without using handler or Broadcast Receiver from service in android. I am confused so please clarify on this discussion.
Answer: Create your activity, register your broadcast receiver et voilĂ  !
Details:
In you question, your refer to service and handlers, which can be started in another thread.
-> Handlers are used for interprocess communications, when a service running outside of the UI thread, should talk with the UI thread.
-> Services are designed for long process cases.
In you question, your refer to broadcast receiver, which can be started from within a service, or from an activity.
->You will always need a broadcast receiver if you want to update the UI with some System (and other custom) events.
->If its just capturing the event and updating a field, this is not a long process. However if it's about capturing and read a database, or accessing a webservice (very asynchrones ops), it's a long process.
to update the UI, you need to have a reference to the view. You can't get references to the views in the service. But you can do it the Activity. That's why you have to enforce the Activity to update UI prior to doing it in the service (since service has no UI itself).
You can pass the reference to the UI into the service, but it will likely lead to memory leaks because of Activity and the Service lifecycles can be different, and you may end up with a deadlock where your Service locks the Activity from being GCed, and Activity locks the service.

BroadcastReceiver persistent during the whole activity lifecycle

I have an application that makes async HTTP requests from various places (app activities and a background service). I'd like to catch response events inside my main activity and modify some views. This is achieved by using anonymous class BroadcastReceiver inside the main activity. The registering/unregistering of the broadcast receiver is inside onResume()/onPause().
The problem is that when screen is off and the activity is not in the foreground the events aren't caught, because the receiver is unregistered. How to catch all events even in background while preserving register/unregister coherency of BroadcastReceiver?
Your best bet here would be to start a persistent background service (with a local broadcast receiver).
Here are some starting points:
Your service's onStartCommand() should return START_STICKY, so
it's not killed by the OS.
You should create a local variable inside
the Service that holds your broadcast receiver and register this
receiver in onStart() and unregister it in onDestroy().
Start the
service whenever you find suitable (e.g. onCreate() of the
Application, since it's only called once per application life-cycle
and is not tied to a specific Activity).
This answer might help.
Your existing approach doesn't work because when the screen is turned off, the onPause signal is sent to all your activities and they automatically unregister the local broadcast receiver (and they should be).
There two alternatives
Have a service running and register the receiver there instead.
You can register the broadcast receiver in the manifest and handle it there. Please keep in mind that the receiver will run on the main thread, so you should signal to a running service perhaps a service that performs a single task.
A service that performs a single task can be implemented using IntentService. It is kind of like an async task wrapped in a service.
I solved the problem by adding EventBus lib. The handler is implemented inside the main activity, activity subscribes for events on onCreate() and unsubscribes on onDestroy(). Since EventBus lib is built on standard Java components I expect the garbage collector to automatically clean up everything even if onDestroy() is not called.
Futhermore I used WeakReference for my views which allows to check if an activity is already disposed to prevent unexpected errors.
This may be not the best solution, but it works for now and much easier to implement than other proposed answers.

Prevent Service to restart

I have an IntentService which is started from a BroadcastReceiver with startService(service). When I get new informations in the BroadcastReceiver the new infos are pushed through an intent with startService(service) again to the IntentService but then the service is restarted. Can I prevent this? I want to push new informations to the IntentService without restating it.
Intent service are intended to be started with an intent, execute their job and finish. They are more like an asynctask from this point of view. This is the reason why your intentservice is restarting.
onHandleIntent should do some work and finish. You could do some tricks to make it blocking but that would go against the nature of intent services.
What you should do is to have a classic Service. If you are getting ANR errors, you should perform all the time intensive operations inside a thread or an asynctask hosted inside the service itself.
I assume you need to share some state for handling subsequent Intents inside your Service. I see two solutions:
Use IntentService and save and restore this state inside onHandleIntent.
Use started Service, and hold this state as a field inside your Service class. To prevent ANRs, process the Intents outside of UI thread, just like the IntentService does. To keep the Service running, just remove the stopSelf call from handleMessage.
If you can get away with restoring and saving state for each processed Intent, the first solution is safer, because your Service may be killed by the OS in case of running out of memory.

Calling a lengthy Service method from an Activity - Best Practice

I'm developing an app with a service that forwards calls to a web-service, and a few activities that place those calls. The activities need to process the results of those calls. For example, I have a writeComment method on the service, that accesses the web-service and returns some information about the newly written comment.
Right now I let the Activity take care of all the threading. The Activity binds the service, and then uses an AsyncTask that calls the bound service's writeComment method.
All works well as long as the Activity isn't stopped while the AsyncTask is running. If it does (easily happens when flipping the phone), the AsyncTask dies a violent death when trying to update the UI in onPostExecute. I'm not entirely sure how to fix this - I do need to let the user know the server has been updated.
If I go the other way around, and register a callback with the Service, I'm still a bit stump, because I need to notify the Service the Activity has changed - I need to tell it not to notify me in the first Activity's onDestory, and reregister in the second Activity's onCreate. And I need to handle the case where the asynchronous task completes after onDestroy and before onCreate.
What is considered Best Practice in this case?
Thanks,
Itay.
My intuition tells me to let the service handle the threading. Services are far less transient (although still transient to some degree) than activities and therefore you'll have less issues of threads trying to interact with a Context (be it an Activity or a Service) that's no longer there. Have you looked at the IntentService class? It handles a lot of the threading for you.
In my app, I have a long-running service and Activities that need to render data in the service. The service also pings the Activities when there is a change but the Activity can also query the service. The way I approached this was two-fold.
Firstly, I bind my activity to the Service in order to send messages from Activity to service.
Secondly, the Service sends notifications with Broadcasts and the Activity listens for those broadcasts. I set that up in the Activity onResume and tear it down in the onPause. I think this is the part that you're missing.

Asynctask inside BroadCastReceiver

I want to use an Asynctask inside BroadCastReceiver so that I can show caller information when I receive a call.
Can someone tell me how to do this.
Regards,
Shankar
You shouldn't use background tasks with broadcast receivers. Broadcast receiver component is considered destroyed as soon as it returns from its onReceive() function. And if this was the only component in process, the process can get killed at any time.
If you need to run some background task as reaction to received broadcast, start a service and run background task as part of Service component.
Before Honeycomb (API11), you had to use a service.
Since Honeycomb (API11), you can use goAsync() :
This can be called by an application in onReceive(Context, Intent) to
allow it to keep the broadcast active after returning from that
function. This does not change the expectation of being relatively
responsive to the broadcast (finishing it within 10s), but does allow
the implementation to move work related to it over to another thread
to avoid glitching the main UI thread due to disk IO.
Also, in order to show somethign while the phone is ringing, you will have to create a foreground service that keeps an on-top view alive , as shown here.

Categories

Resources