What to do if OS has killed an IntentService? - android

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.

Related

Is it correct to call WebServices inside onReceive of BroadcastReceiver?

I've a BroadcastReciever on a separate class, i register that receiver on one of the activities, and this broadcast receiver trigger when there is an Internet connectivity. Inside onReceive() of the receiver, i execute a method for getting token from the server.
But when i gone through the documentation i found that; "When it runs on the main thread you should never perform long-running operations in it (there is a timeout of 10 seconds that the system allows before considering the receiver to be blocked and a candidate to be killed)."
Please help me with the correct way of doing it.
IMO , it is perfectly fine to call a WebService inside the onReceive method of a broadcast receiver. I have done it in many of my applications and till now I have never faced any problem.
Infact in majority of applications, which require frequent updates from server the BroadcastReceiver component is used as the onReceive method runs in the Worker thread/task.
To be on the safe side you can set your WebService timeout to less than 10 secs.Another implementation can be that you can create a background/worker thread, send it a token from the onReceive of your BroadcastReceiver and inside that thread you can call your WebService.
No, The Android System may be kills the your BroadcastReceiver, in case of in-sufficient memory. Because user never or not recently interact with the process of Application.
A process that is currently executing a BroadcastReceiver (that is, currently running the code in its onReceive(Context, Intent) method) is considered to be a foreground process and will be kept running by the system except under cases of extreme memory pressure.
That means A Process holds only BroadcastReceiver, then it may be considered as low priority under cases of extreme memory pressure.
This means that for longer-running operations you will often use a Service in conjunction with a BroadcastReceiver to keep the containing process active for the entire time of your operation.
Intent intent = new Intent(mContext, MyService.class)
intent.setData(Uri.parse(your_url));
mContext.startService(intent);

Is IntentService queue is maintained when service is killed (closed)?

Currently, I developing SNS application that can post comments on a article. and I want to process some network processes in background (e.g. Service, etc.). But I have some worry about that. Is it safe when user killing the application If I implement that features through IntentService?
I have planned all of 'Comment Request' stores into IntentService queue. but It takes a risk when user kill the application. (I guess Android OS have to destroys IntentService Queue)
So, I want to question about that. IntentService's intent queue is maintaining when user close (kill) the application? If not, how I handle this problem? using database or something to save IntentService queue? Absolutly, I have no idea with this.
If the user kills the application, services are safe. If they wish to go into their phones application manager and stop the service, that's entirely different, something that can't be stopped, so that's when the service would end. Your intent service will be fine. For more information: [https://developer.android.com/training/run-background-service/create-service.html]

Please, explain some Android Service Concepts

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.

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.

Is it possible that an IntentService will be killed before the Activity using it?

I have an application that has an IntentService to provide background processing - specifically it fetches data from the net and stores it in an Sqlite database.
My Activities use Context.startService() to request the service to update data, and the service sends a local broadcast message when the update is complete.
The IntentService uses a thread pool to do the work - primarily in case a new Activity is opened before a request is complete, so a new request for a different resource won't block waiting for the previous one to finish.
That all works fine, but in order to prevent multiple simultaneous requests for the same resource, I set a flag in the activity after it has sent a request which stops it sending new requests until it gets back a DONE message from the service.
Now if the IntentService was killed off in the middle of an operation it will never send the DONE message, and the Activity will never know that the request is unfulfilled, and will not re-request the resource. Is this possible? And if it happens is there any way for the Activity to be informed?
Is this possible?
So long as you are catching all possible unhandled exceptions, no. Components are not "killed" individually for, say, memory reclamation -- that is done on a process-by-process basis.
If you are concerned about this then send a broadcast flag in the onDestroy of the IntentService (or just set a breakpoint so you can see if it is being hit). The IntentService is intended as a simplified service which handles its own lifecycle so if you are passing work from the service to a thread pool it's possible the IntentService believes it finishes its work - you can catch this in onDestroy.
Obviously can't say if that is happening without looking at the code but this mechanism will let you check if it is.

Categories

Resources