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.
Related
I use a service to process intents with ContentResolver in the background.
Each new intent calls starts the service and the service stops itself once the processing is over.
This creates an issue where new intent starts a service run but the previous service run is still processing, resulting in killing the new run before its processing is over.
I thought about adding some kind of static 'nunInstances' in the service and stop it only of it's 1.
Another option is leaving the service running. I've tried looking for information about it's validity and side effects but came up empty.
You can use an IntentService, which acts as a work queue. You can send it work to do with startService() as many times as you like. The work is performed serially, one after another. When the last work unit has been performed the Service stops itself.
Or you use a regular Service and queue the work yourself in onStartCommand(). When you have no more work to do, you call stopSelf().
NOTE: Android will not create more than one instance of a Service. Your concern about having multiple instances of the Service running is not necessary. If something calls startService() and the Service is already running, Android does not create a new instance of the Service. It just called onStartCommand() on the running instance and passes the Intent as a parameter.
I'm just approaching Android Services, but i have many doubts. Here there are some questions.
Before starting, notice i have read those pages
Android Services (official)
Bounded Services (official)
plus sone Inner classes theory in my language. Please be patient, i'm still a bit confused.
1) First of all, a Services differentiates itself from an AsyncTask mainly because it continues to run also if the app is paused (i.e. the user is watching another app); AsyncTask is stopped in that cases. Is it ok or am i wrong?
2) A Service runs in the same thread of the activity that started it through startService().
To not affect the Activity's performances, i have to create a separate thread for that Service, for example implementing the Runnable interface. Another method is making a service that extends IntentService, which automatically provides a new thread for the service: a new thread is created on any onHandleIntent() call.
Now, let's look at my concrete problem. I need to create a Service that will be used by many Activities: his task will be to connect to the server DB every 60 seconds and check for news. If a news is found, notify there's a new news (if we are on MainActivity) or show the new news's title (if we are in the news reader). How should i code it?
I have made a MainActivity that instantiate a NewsService and immediately calls startService(). On the other side, i have the NewsService extends IntentService, that (creates a new thread when onHandleIntent is called?) and looks for new news. Is it a bad idea to use a IntentService? I realized it will be very ugly to start the service calling startService() indefinitely.
At the start of this exercize i tought it was a good solution because it automatically creates a new thread and makes Service implementation simple. But now i have some doubts (i can't know if there's a news! How can MainActivity know it? And how to get the title)
This should be done with a normal extends Thread class, that makes an infinite cicle in it's run() method, checking for news every 60 seconds and, if there's a new one, reads the title from remote DB AND update activities buttons/views. Then if the App will be closed by user, the Service will be closed too.
But the problem is that if i istantiate such class it's work will be stopped when the MainActivity is paused or stopped, and other Activities (the NewsReader in this case) cannot get any update because the new thread isn't getting news at the moment. So i need a Service.
I hope it's clear. How should i implement a solution in the right way?
Please highlight everything wrong in my text, i really need to learn :D
You seem to have understood everything correctly.
As to your specific problem, I'd recommend the following:
Use AlarmManager to schedule your service. Don't let the Service run when it does not have to.
Use a Broadcast Intent for new news. All Activities will have to have an inner BroadcastReceiver that listens for the Broadcast intent of the service and reacts accordingly.
Services are a good approach for what you want, they are pretty good to do processes that consume few resources like keeping a daemon in background, they are also good to show notifications without an activity and keep running even if you exit the activity.
When you need to do more heavy operations in your service you can still use an AsyncTask, launch it, execute your operation in another thread and automatically receive the result in your main thread.
If you want to keep the service always running you can use START_STICKY in your Service
#Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
// Ensure the service will restart if it dies
return START_STICKY;
}
And you can launch the service doing:
final Intent service = new Intent();
service.setComponent(new ComponentName(YourService.PACKAGE_NAME,
YourService.SERVICE_FULL_NAME));
// Start the service
context.startService(service);
1) First of all, a Services differentiates itself from an AsyncTask
mainly because it continues to run also if the app is paused (i.e. the
user is watching another app); AsyncTask is stopped in that cases. Is
it ok or am i wrong?
This is not correct. AsyncTask is a mechanism for offloading background processing into a separate thread and provides a mechanism for informing the user of progress, error and completion of that background processing. AsyncTask does not stop working if the app is paused. It continues to perform its processing in the background. In general, there is tight coupling between an AsyncTask and the Activity that started it.
A Service, on the other hand, is (generally) completely decoupled from the Activity that started it. A Service has its own lifecycle which is independent of the other activities in the app. Also, services have no UI, so they are not linked to the visual elements of the application and they provide no (direct) mechanisms for visual feedback related to progress, error or completion. This needs to programmed separately.
2) A Service runs in the same thread of the
activity that started it through startService(). To not affect the
Activity's performances, i have to create a separate thread for that
Service, for example implementing the Runnable interface. Another
method is making a service that extends IntentService, which
automatically provides a new thread for the service: a new thread is
created on any onHandleIntent() call.
This isn't correct either. A Service doesn't run on any specific thread. The lifecycle methods of a Service (onCreate(), onStartCommand(), etc.) run on the main (UI) thread, which may or may not be the same thread that called startService(). However, a Service can (and usually does) start other background threads, as many as it needs to, to perform the necessary work.
IntentService is a specific kind of Service which manages one or more worker threads that it uses to perform background processing. You send a "command" to an IntentService and the IntentService then puts your command in a queue. At some point (different implementations in different Android versions behave differently), your "command" is dequeued and processed in a background thread. IntentService stops itself after all the "commands" have been processed. IntentService is often not the best choice for a Service due to the way it behaves.
IntentService is definitely not what you want in your case. You should probably use AlarmManager and set an alarm that starts your Service every minute. When your Service starts, it should create a background thread that contacts your server and checks for news. If there is no news it can just go away. If there is new news, it can either start your Activity to inform the user, or it can send a broadcast Intent which your Activity will see (if it is running),or it could create a Notification which the user can then open whenever he wants to. You need to figure out how you want to determine when the app should stop checking the server. Maybe the user should tell you that he isn't interested anymore, or maybe the Service can recognize that the app isn't running anymore (or hasn't been looked at in more than X hours or whatever). There are lots of ways to do this and it depends on your requirements.
Let's say we have an implementation of IntentService, then we start it from Activity and then add several other Intents in a queue to IntentService for processing. So now we have first Intent under processing and the rest of Intents in a queue. Now let's imagine the OS kills our Application process because of understandable reason. The questions are:
How to restart the IntentService?
How to restore the queue?
Well, I know there is always a Service where you can override it's onStartCommand() and tell a Service what to do. But I need an IntentService because of its queue model.
IntentService is not what you want to use if the queue of work needs to be persistent. If you send many Intents to an IntentService and then the process is killed by Android, there is no way to rebuild the queue. IntentService simply queues the Intents up using an internal Handler and these are not persisted anywhere. They just get lost.
If I were you I would just implement this myself. The code for IntentService isn't that large and you can look at it and use it as a model for your own Service. You'll want to write your queue to a database so that it is persistent. Return START_STICKY from onStartCommand() so that Android will automatically restart your Service if it is killed due to resource requirements.
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.
I'm about to develop an application for Android.
I need to continuously run an update thread that executes a task in a given interval. And this thread needs to be shared between activities.
I would also like to notify the active Activity when the thread executes a task.
In iOS I would execute a thread from the AppDelegate and then send notifications, but how do I achieve this with the Android SDK?
I'd say create a Service that does the work for you. When it starts or finishes (or at any point you want), you can send a custom broadcast intent to indicate all parties that your service has passed this point. See Intents.
If you want to start this Service periodically, also have a look at the AlarmManager. That allows you send a broadcast intent periodically - in this case the intent that starts the service.
Also note that it's usually wiser to to terminate a service via stopSelf() when it's work is done. Run it again via intent when needed. Keeping it alive all the time isn't a good idea when it comes to battery life.
Make a service and implement a thread with infinite loop and from there you can do your job....to update data in activity you can make a static method and you can call it from there with appropriate arguments....