What happens in android when i have an intentService that gets called multiple times before onHandleIntent completes. Let me show you an example:
say i have a intent service that looks like this:
public class AService extends IntentService {
public AService() {
super("AService");
}
#Override
protected void onHandleIntent(Intent intent) {
// magic happens here but lets pretend it takes 3 mins.
}
}
Now lets say i call this service multiple times, do the requests get queued ? How is concurrency handled or am i expected to handle it by putting a synch block in onHandleIntent like this:
synchronized (AService.class) {
//do stuff here
}
Now lets say i call this service multiple times, do the requests get queued ?
Yes, assuming that by "call this service", you mean call startService() with an Intent that resolves to this service. Quoting the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Related
I know there are many ways to call a function every x seconds or schedule a job. My question is what is the best fit solution for my problem?
I have a heavy task that I want to run in a background thread (Database queries, making HTTP calls).
For this I use an IntentService since it's onHandleIntent function runs in a background worker thread and the started services are queued.
The queue doesn't really matter for me since startService() will only be called from one place.
Now, I want to start this service frequently, sometehing like 10-15 seconds.
This was my old solution:
class MyService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
mutex = new Object();
while(isServiceRunning) {
doTheBigJob();
syncrhonized (mutex) {
mutex.wait(15000);
}
}
}
}
I assume this is bad practice.
Now my Intent service only contains doTheBigJob(). But how should I time my startService() call to make this happen every 15 sec for forever. What is the most optimal way?
This is a KIOSK app so it will always be in the foreground and the user can't escape it.
How do I run a parallel action (process) to the main app in Android?
I know that, there are a lot of ways to do it: Threads, Tasks, Handlers and etc'...
This is the way I chose. But I think it takes a lot of memory and doesn't closes in the interrupt call.
checkReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: Check is this a good way to handle threads
Thread t = new Thread() {
#Override
public void run() {
internetConnectionManager.TryConnect();
this.interrupt();
}
};
t.start();
}
}
};
Two things wrong with your arroach:
You should not start a thread in onRecieve method. The reason is explained here :
This has important repercussions to what you can do in an
onReceive(Context, Intent) implementation: anything that requires
asynchronous operation is not available, because you will need to
return from the function to handle the asynchronous operation, but at
that point the BroadcastReceiver is no longer active and thus the
system is free to kill its process before the asynchronous operation
completes
Second, calling Thread.currentThread().interrupt() does not make any sense in your example since your thread is already done by that line and will finish, and also because you don not check interrupted flag anyway.
The better way, in my opinion, would be to start a simple IntentService from your onReceive code. Here is a simple tutorial.
Important edit based on FunkTheMonk's comment:
If the broadcast comes from an alarm or external event, it is possible that your device will go to sleep shortly after onReceive returns (even if you create a service). If that is the case, instead of using regular BroadCastReceiver you should extend WakefulBroadcastReceiver from support library.
Use handler
if you want to stop handler then fire an intent with some value eg.("quit handler")to receiver
and call remove call back and inside handler you can handle the rest using ACTION switch
you can also use intentservice
My Android application has to:
upload an image to the server
make 3 ( quick ) calls to a REST web service using the uploaded image image
get output from webservice
display output on ui.
I'm confused about whether I should use a Service or AsyncTask.
I think I should use an AsyncTask because the tasks need to be done in the background and the outcome needs to be displayed on the UI once the process is complete. The doInBackground() and postExecute() methods seem perfect for this sort of thing.
However, I've read from the Android Documentation and several StackOverflow answers that using Services is more appropriate. The problem is that I want to display the output on the UI as soon as the task is complete. If the user quits the app, then I want the upload to stop.
I'm confused: Is AsyncTask really the better choice?
You should create an IntentService. Send an intent to the service to start it. Send back an intent with the result using a LocalBroadcastManager (from the support library). The IntentService stops itself when it completes, unlike regular Services.
If the user rotates the device while the AsyncTask is executing the result will be lost since the AsyncTask thread is associated with the activity that was destroyed by the rotation. You can find an example here on StackOverflow of how to circumvent this problem, but it's much more code and more complex than writing an IntentService. Since the IntentService is on its own thread, it doesn't get lost when the activity is destroyed.
public class MyIntentService extends IntentService {
public static final String SERVICE_NAME ="whatever";
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
//Get input from the intent, do your http stuff here,
// create a new intent to send back
LocalBroadcastManager.getInstance(this).sendBroadcast(intentToSendBack);
}
}
Check out the IntentService docs: Intent Service is about 1/3 down the page
Use a LocalBroadcastManager in your activity to listen for the returning intents. You just hook it up in the OnResume event handler and unhook it in the OnPause handler. So after your original activity is destroyed on the rotation, the new one will start listening. The magic of LocalBroadcastManager queues up the intent for that small period of time between the destruction of the first activity and the creation of the second.
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(MyIntentService.SERVICE_NAME);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, filter);
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
}
private BroadcastReceiver onNotice = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do your UI stuff here....
}
}
There is more detail on LocalBroadcastManager in the docs. There are some other good side effects of LocalBroadcastManager. Intents sent this way do not leave the application scope, so other apps can't snoop on data you pass around, and your activity processes the result without being forced into the foreground.
Don't forget to register the service in your AndroidManifest.xml.
IF you are doing network related stuff in your app you need to use an AsyncTask no matter what you do because you will get a NetowrkOnMainThreadException. you are not allowed to do anything network related on the UI thread. Since a service runs on the UI thread you will still need an AsyncTask in the service.
So if it were me I would not worry about the service if you need to update the UI when its done
Having read most of the available documentation on Android services on the developer site and here in stackoverflow, I'm still confused by several aspects of running a service in a separate task. Hopefully someone can put me on the right track.
Let's say we have trival service framework such as
public class HliService extends Service {
#Override
public void onCreate() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
}
}
and in the manifest, I have
<service android:name=".HliService" android:process=":HLI_Comms"/>
so that the service runs in its own thread.
The intent of the service is to provide a background task that will communicate
to a device using a TCP socket and do some other stuff. At the risk of ignoring battery issues etc, basically I'd like it to run forever.
Something like
// Method that communicates using a TCP socket, and needs to send
// information back to the activity and receive messages from activity
// not shown here.
private void dummytask() {
boolean keepGoing = true;
while (keepGoing) {
// do useful stuff in here
// sets keepGoing false at some point
}
stopSelf();
}
What is the best way to initiate this method/task ?
I have looked at code in the developer site that uses a message handler and a looper, which I only partly understand, but it seems very complicated and perhaps more than I require?
I don't believe I can call this method from either onCreate() or onStartCommand() since then neither would complete when invoked from the system ? Should I start it with a timer or alarm?
I will need to add a message handler to communicate with the the gui activity, but since I'm starting the service in another thread (by virtue of the manifest "process" instruction), do I need to use AIDL instead?
I have also looked at using AysnchTask rather than extending Service, but it seems better suited to running a task and then terminating.
so that the service run in its own thread.
That puts the service in its own process. This is generally something to be avoided, as it consumes extra RAM and CPU (for IPC). You can create a thread just by creating a Thread or any number of other means, most of which have been in Java for a decade or so.
At the risk of ignoring battery issues etc, basically I'd like it to run forever.
It is pretty much impossible for a service to run forever. Users or the OS will get rid of your service eventually.
What is the best way to initiate this method/task ?
Call dummytask() from a background thread.
do I need to use AIDL instead?
No. Your service can broadcast an Intent, or invoke a PendingIntent supplied by the activity, or send a Message via a Messenger supplied by the activity, etc. The best would be to use the LocalBroadcastManager from the Android Support package, but that will not work across process boundaries, forcing you into more expensive communications options.
I think you could use a IntentService which you run by setting up a (regular) alarm (AlarmManager.setRepeating) with a PendingIntent in it. You can notify the UI by broadcasting an Intent from the IntentService and receiving it in your UI through a BroadcastReceiver.
I'm using a repeating alarm to trigger a BroadcastReceiver (OnAlarmReceiver) which in turn calls WakefulIntentService.sendWakefulWork(context, PmNotificationService.class);
The doWakefulWork method is displayed below
protected void doWakefulWork(Intent intent) {
// Load auth information from server
Authentication.loadAuthenticationInformation(this);
if (hasAuthInformation()) {
getRequestParameters().execute(getRequestHandler());
}
}
The getRequestParameters().execute(getRequestHandler()); line creates an AjaxRequest object, along with a RequestHandler object, and the idea was that once the Ajax request is completed, it would send the information back to the RequestHandler.
In this case the handler is the PmNotificationService class (which extends WakefulIntentService).
The problem, and thus the basis of my question is the following message:
05-12 12:09:08.139: INFO/ActivityManager(52): Stopping service: com.sofurry/.services.PmNotificationService
05-12 12:09:08.558: WARN/MessageQueue(333): Handler{4393e118} sending message to a Handler on a dead thread
05-12 12:09:08.558: WARN/MessageQueue(333): java.lang.RuntimeException: Handler{4393e118} sending message to a Handler on a dead thread
...
Obviously the service stops running as soon as it has sent off the request, as that request runs in another thread, and as a result hereof the Handler is dead.
So my question is: Can I keep the service and thus the handler alive until I get a response (ie. wait for that other thread)? I would prefer it if I could, as the AjaxRequest object is maintained by someone else, and is used throughout the entire application.
Update
I obviously missed one very important point, namely that the WakefulIntentService inherits from IntentService instead of Service which means it will stop itself after it has done its work. I have currently solved it by changing the doWakefulWork method slightly. Here's the new one:
#Override
protected void doWakefulWork(Intent intent) {
RequestThread thread = null;
// Load auth information from server
Authentication.loadAuthenticationInformation(this);
if (hasAuthInformation()) {
thread = getRequestParameters().execute(getRequestHandler());
try {
thread.join();
} catch (InterruptedException ignored) {}
}
}
I'm not sure if using thread.join() is the best way to manage this, so I'll leave the question unanswered for a few days, before I post an answer, just in case someone has a better solution for it.
IntentService already uses a background thread for onHandleIntent().
Hence, do not use AsyncTask -- just execute your code in onHandleIntent().
Check https://groups.google.com/forum/#!topic/android-developers/YDrGmFDFUeU