I have an app that runs certain "long" process when it is opened or when the device is booted.
The process performs certain amount of downloads via the download manager, and when the process finishes it sends a broadcast event to the app, to capture some analytics.
As I understand, whenever the boot broadcast event is called, the Application class is intantiated (if not in memory already).
Application class is also initiated when the user opens the app.
Based on that, the code to run the proccess is placed inside onCreate method of the Application class. (the process starts a new thread from there)
However, it appears that the "long" process is taking more than the time-to-live of the boot broadcast receiver (about 10s?), so the app process is killed. Then a couple of seconds later, after the download is finished a second broadcast is sent and the app is started again calling Application.onCreate again, with some undesirable effects.
The process was expected to run in a single linear way and not calling again onCreate.
As this process happens only once, I was thinking on creating a Service to give more time to the app to stay alive. However the process depends on DownloadManager so:
1) Using IntentService won't work (as I understand) because the process is still killed after handleIntent returns. The process creates new threads so its tasks are async, and handleIntent method will return before the whole process finishes.
2) Should I create a Service which is simply 'alive' for some time and then is stopped after the process finishes?
3) As an additional question, if I have a running Service, will Application class be instantiated and kept in memory until the Service is stopped?
If you do this only once, you should just create your own Service. When your app starts, call startService(). In onStartCommand() of your Service, start a background Thread that does what you want and return START_STICKY (This keeps your Service running until you stop it). When the Thread completes, call stopSelf() on the Service.
Of course, you can use IntentService, but that class is just an extension of Service that provides another layer of convenience for you. IntentService manages a pool of background threads and takes care of starting and stopping the Service when it runs out of work. This is probably overkill for what you need, but go ahead and use it if you want. The tradeoffs here are negligible.
NOTE: <opinion>For some reason, lots of developers seem to like certain "fad" solutions, like AsyncTask, IntentService, and Event Bus. There are plenty of other ways to solve problems. There is no "one size fits all" in software development.</opinion>
You could still use an Intent Service, you just need to block while the background task is running. Implementation could work like this:
Put it in a service, an IntentService could work like so:
public class DownloadIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
//get url or whatever from intent
//kick off async code to start the download, something like eg:
DownloadTask downloadTask = new DownloadTask(url);
downloadTask.setListener(new Listener() {
public void onComplete(Download download) {
DownloadIntentService.this.notify();
}
}
downloadTask.start()
wait();
}
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.
What is the cons of using Thread instead of using Android Service in an App for long running task. What will happen if I don't use Android Service for long running task?
Service:
A service is a component which runs in the background, without direct interaction with the user. As the service has no user interface it is not bound to the lifecycle of an activity.
Services are used for repetitive and potential long running operations, like Internet downloads, checking for new data, data processing, updating content providers and the like.
It is possible to assign services the same priority as foreground activities. In this case it is required to have a visible notification active for the related service. It is frequently used for services which play videos or music.
Threads:
They are simple runnable threads. You can execute non UI stuff with these threads but you can't perform UI tasks in them (as UI is not thread safe). For dealing with UI in these threads, you will have to use Handlers, which is quite cumbersome for beginners to get a grip and understanding of them.
So depending on your needs and app you can choose the one best suits you.
A Service is an application component that can perform
long-running operations in the background and does not provide a user
interface. Another application component can start a service and it
will continue to run in the background even if the user switches to
another application. Additionally, a component can bind to a service
to interact with it and even perform interprocess communication
(IPC). For example, a service might handle network transactions, play
music, perform file I/O, or interact with a content provider, all
from the background.
On other hand, Threads are the cornerstone of any multitasking
operating system and can be thought of as mini-processes running
within a main process, the purpose of which is to enable at least the
appearance of parallel execution paths within applications.
They are to be used as per requirement and we cannot actually point out pros and cons of either of them as both of them are essential in different situations.
What will happen if I don't use Android Service for long running task?
You might get lucky and your code finishes. Then again, you might not get lucky, and your code gets killed at a random point in time.
Aside from the textbook descriptions of what an Android Service is and what a Thread is, the main difference between the two which is directly relevant to your question is how the OS threats them.
A thread is a way to execute code in the background, while a service is a way to make Android aware you are executing code in the background.
As far as the underlying Linux kernel is concerned, it knows only about threads, and cares about them only with regards to thread switching and prioritization. Whether there is a service has no impact on this.
However, as far as the Android device memory management and task prioritization goes, Android does not know or care about threads in your process. It only knows about services, and interacts with them on the main app process thread only.
Thus, for as long as you have a thread alive, the kernel will happily try to keep the process alive and allocate CPU time for that thread execution.
However, unless you have an activity, service, content provider, or a broadcast receiver alive, the Android memory manager might decide to kill your process to reclaim its resources for another higher priority process, no matter what threads might be working at this point.
Therefore, while you could go away with running stuff on a separate thread if the user is interacting with your activity, if you want to make sure the background task finishes successfully and is not interrupted at a random point, you need to wrap it in a service (preferably one that is bound by an activity, or is elevated to UI priority by showing a notification).
Note that having a service does not guarantee you that its code will be running in the background. Android will call the lifecycle methods (onStartCommand/onBind/onCreate/OnDestroy) on the main thread of the application process. Your code will have to start a thread to ensure true background execution.
Services are highly recommended and used in Android to do both foreground and background tasks. Instead of going into the definitions I would highly recommend you to look into IntentService class specifically in Android. Available from API Level 3 this class does most of the worker thread heavy lifting for your background task. This class handles asynchronous requests expressed as Intents. Clients send request using startService(Intent) calls. The service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work. Coolest thing you can use this along with an AlarmManager implementation to do say what you want to do every 10-15 mins and still not worry about threads and handler explicit implementation as you would have to if you use Service class.
Here is a short bit of code on how to implement it.
public class UpdateService extends IntentService {
public UpdateService() {
//constructor
}
#Override
public void onCreate() {
super.onCreate();
//Called by the system when the service is first created.
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStart(intent, startId);
return(START_REDELIVER_INTENT); //Intent Relidelivery
//You should not override this method for your
IntentService and remember onStart() for IntentService is
deprecated.
}
#Override
protected void onHandleIntent(Intent intent) {
//do your main background tasks here forget about threading doing anything
in here Android will do the heavylifting as required
}
#Override
public void onDestroy() {
super.onDestroy();
//finalize your objects GC etc here
//Called by the system to notify a Service that it is no longer
used and is being removed.
}
}
Services are best implementations for long running tasks that you don't need user input or ui updates right away. If you absolutely don't need to don't use threads and handlers since you might come across a lot of concurrency / deadlock etc issues.
Hope this helps.
Nothing will happen, I ran an algorithm in a async task about 90 hours. Worked fine.
Async Task: seperate a "heavy" task from the UI, for example a download
Service: seperate a task from the App, for example an alarm clock
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.
I have a class that implements fileuploader service. Activites bind to it and supply it a list of files to be uploaded, and then unbind immediately. The files are then uploaded one-by-one by the service in a background thread(asynctask).
I start this service in my dashboard actvity using startService(), so that it keeps running until specifically stopService() is called.
Now, my question is when do I stop this service?
Basically I need to check two conditions: 1: all files are uploaded; 2: app has exited.
Also, to exit the App, user has to press back button on dashboard activity.
I could have overrided back button press and queriesd the service whether any files are left, but I dont want to use that method.
Any suggestions?
Activites bind to it and supply it a list of files to be uploaded, and then unbind immediately.
I would recommend then using startService() rather than bindService().
The files are then uploaded one-by-one by the service in a background thread(asynctask).
This seems like a much better fit for startService() and an IntentService (or a WakefulIntentService perhaps, if you are concerned about the device falling asleep during uploads).
I start this service in my dashboard actvity using startService()
This would not be needed if you used startService() for sending over the work.
so that it keeps running until specifically stopService() is called.
Ideally, the service would shut itself down, like IntentService does. After all, only the service knows when the service is done.
my question is when do I stop this service?
When you have no more work to do. IntentService does this automatically. If you really want to maintain your own thread pool for doing the work, then when your work queue is empty and all threads are done, call stopSelf() from within the service.
Basically I need to check two conditions: 1: all files are uploaded
Yes.
2: app has exited
No. Your UI should not care whether the service is running or not running. The service should take care of itself.
Also, to exit the App, user has to press back button on dashboard activity.
Users are welcome to leave your app however they please: BACK, HOME, RECENTS, a Notification, an incoming phone call, etc.
Any suggestions?
Use an IntentService. Send over the jobs to be uploaded via calls to startService(), packaging all needed data into the Intent used with startService() (e.g., extras). Do your upload work in onHandleIntent(). If desired, use LocalBroadcastManager to let activities in your app know about the upload status, so they can reflect that in their UI if they so choose. IntentService will handle stopping itself when its work queue empties.