I am working on an application which needs to do a WiFi scan every 5-6 seconds. WiFiScanner class is implemented as a service and called from the main Activity. In order to repeat tasks every few seconds, I have used Handler with postDelayed with an interval of 5000 msecs. After installing on the device the application runs fine first time. Stopping the WiFi scan process, closing and immediately reopening the application causes it to crash. I suppose its because I haven't stopped the Handler explicitly in the main activity by calling removecallbacks on the runnable, instead clicking stop would simply stop the service. Here's what logcat throws on the error.
06-14 12:30:58.181: ERROR/AndroidRuntime(23534): java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.SCAN_RESULTS } in com.test.example.WiFiScanner$1#2b0a3880
I was looking through stackoverflow and found suggestions to use an AlarmManager instead. But wouldn't this require me to implement a BroadcastReciever class for the purpose as it says here? Is there any other alternative to Handler to doing repetitive tasks in a service invoked from the Main Activity?
well you can just bind the service instead of starting it. that means it's a local service which will get stopped when there arent any more activities bound to it. but be carefull because the service runs in the ui thread so move things in a background thread. what i have commonly used in situations like this is a handler that postDelayed a runnable executing an async task where you can do whatever you want to do and then rescheduling it so it runs in some time period. also remove the callbacks when the service is destroyed and start it sticky so that if it is killed it restarts and you can also remove the callbacks on start.
As an alternative you can use an intent service or a simple service with alarms that is started by the alarm on specific time periods, that calls selfStop after it has completed a scan. but if you are running frequent checks then this creates an overhead because the service needs to be created over and over again (so better keep it running then).
there is also the timerTask class but i simply find this 2 solutions better. the timer class introduces a new thread
see: Timer
And This for an implementation
and here is someone that tried to do the same thing as you are:
Timer task and answers
Related
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();
}
I have encountered a problem while writing tests for my activity which made me wonder about this issue. I'm using ActivityInstrumentationTestCase2 and my activity sends intents to the service using startService when a button is clicked and it works fine. (My service is a singelton so i can know if it is running)
When in testing I'm doing the following:
assert service isn't running.
send intent to start the service (or press the button tried both)
wait for the service to start and assert it is running
sounds pretty simple but when i try to wait using Thread.sleep the service wont start, and same for when i try doing busy waiting. So i assumed it will need to finish the testMethod to start the service and i made the following design:
Thread helper;
#Override
tearDown() {
if (helper) join helper
super.tearDown
}
testMethod() {
assert stuff
send intent
start helper
finish
}
helperMethod() {
wait for service to start
assert stuff
}
this actually works, my guess is that it lets the main thread to finish the testMethod and then the intents are handled and my test finishes. This behavior seems very odd as i would expect that the service will start immediately as it is on the same thread or sleeping for enough time will let the service start. So anyone knows what are the conditions for the service to start, and when it happens?
Services are running on the main thread. So if you call Thread.sleep() your service won't start until the time is up.
From the Service document http://developer.android.com/reference/android/app/Service.html
Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work.
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.
I have an activity MainActivity.java. From OnCreate() method of main acitivity I have Started one service which connects to rabbit mq messaging server inside of the OnCreate() method of MyService.java(it extends Service). The issue is that the acvitiy screen take too long time to show because the rabbit mq connection establishment taking long time due to slow network..Then my app shows ANR message , how to overcome this and where to call startService to avoid anr message
You need to handle your connection on a different thread. You have several options.
Thread
Runnable
AsyncTask (preferred method by many programmers)
I would recommend AsyncTask, because there are tons of examples on this site and pretty much everywhere.
You need to do this regardless if you're using a Service or not. Remember that a service runs in the same thread as the User Interface. So maybe you don't even need the Service after all.
EDIT:
You can start the thread anywhere in your application, including in the Activity's onCreate(). If you choose to start the thread in the Service you can also start the thread anywhere including onStartCommand().
I created a service (service B) from Activity (Activity A). And from service B, i created another service (service C). previously the service C used to be a thread not a service. Since it has problems in the long run i changed it to a service. The service C runs a while loop with 3 second Thread.sleep calls. But general condition it do not stop. The Log shows the service is running. But the UI is blocked and after few mins system ask me whether to shut down.
How to make this service non blocking call?
From the service documentation in Android
A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
The best way in this case is to start a new thread and then call a service from there.
Yes, from the documentation, it's clear that services are not separate processes.
Instead, please follow below to make it work:
Start a service from wherever you want to start
In service's class you wrote, write another private class extending thread which will make sure all your background stuff will run in a background thread which is separate from a mail process
Start a thread from onCreate method of service's class. If you start your background work in onStartCommand, you may accidentally start multiple services doing the same task.
Ex. You've given a button on your activity which will start background service. And if you happen to click it multiple times, it'll start those many number of services in background.
Thus, if you use override onCreate method from service, it will check if the service is already running or not and if it's not running, it'll start the service. Otherwise it'll skip and won't start another service.
I think that service C is running on main thread, try create another thread (new thread or asynctask)
Services always run on the main thread.
You need to spawn a background thread or repeatedly run a TimerTask etc in your Service C to avoid blocking the UI thread.
You can start your service in a separate thread like so:
Thread newThread = new Thread(){
Intent serviceIntent = new Intent(getApplicationContext(), YourService.class);
getApplicationContext().startService(serviceIntent);
};
newThread.start();
Please refer to this comment.