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
Related
In my application, a single instance of a class acts like a state machine. Many activities wants to receive updates on the state of this object. The state of this object itself is updated from data from a broadcast of some primitive information.
I have implemented it this way.
I registered a broadcast receiver in the manifest file which receives the primitive information and then starts an IntentService just passing the received information.
#Override
public void onReceive(Context context, Intent intent) {
Intent update_service = new Intent(context, StateMachineUpdateService.class);
update_service.putExtra(PRIMITIVE, intent.getDoubleExtra(PRIMITIVE, 0));
context.startService(update_service);
}
The StateMachineUpdateService keeps an instance and updates it:
#Override
protected void onHandleIntent(Intent intent) {
statemachine.update(intent.getDoubleExtra(PRIMITIVE, 0));
Intent broadcast = new Intent(STATE_MACHINE_UPDATE);
broadcast.putExtra(STATE_MACHINE_STATE, statemachine.get_state());
this.sendBroadcast(broadcast);
}
}
I am wondering if there is an more elegant way to achieve this. I am wondering if starting an IntentService (which in turn will start a separate thread) is something I should try to avoid. The primitive broadcast is sent about 10 times in a second.
Side-question:
let us say statemachine.update takes so much time that the next broadcast has arrived, I would like to ignore those broadcasts. What is the best way to do this?
If you have a singleton object that requires serialized access to its members, one way to go is to use a HandlerThread and schedule incoming work on it from your receiver or wherever else work may originate. The HandlerThread will process everything (runnable or message) in the order it was received (just like the Android main thread).
If you want to skip incoming items of work, you can record the receive time of the work and compare it to the actual time it's being executed, and skip it if the some threshold has been exceeded.
Starting IntentService takes 1-15 ms on my 1 GHz phone. As it is created on UI Thread 10 calls can take even 100 ms which is too much (user will experience lag). You should consider using Hanlder with WorkerThread. You can check how IntentService use this solution and implement it in your case.
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.
I have a thread, and I would like to let the user kill that thread when they click on the progress notification.
My notification works fine, but in my BroadcastReciever I can't manage to kill the thread.
I can't use thread.interupt(), because I don't have access to the thread object. This also means I can't use a public boolean to terminate the thread.
I also tried passing the process id as an extra, and killing it using Process.killProcess(pid), but this has the rather unfortunate side effect of killing my UI thread and any other threads I might have running.
Finally, I tried using the thread id, but the documentation doesn't mention using this for killing the thread.
In short, how can I kill my thread using the primitive data types that can be passed as extras?
You're looking at it with the wrong approach.
If you have a thread running and a notification on the notification bar I'll assume that you have a service running, and this service know the thread and does have a reference to it. That way, the PendinIntent for your notification, should not simply trigger a BroadcastReceiver, but trigger the same Service with an Intent extra indicating that the service should cancel the thread.
so assuming your service:
public MyService extend Service{
private Runnable myThread = new Runnable{
#Override
public void run(){
// ... here you're doing the job on the different thread
}
};
}
something like that:
Intent i = new Intent(this, MyService.class);
i.putExtra("cancel", true);
PendingIntent pi = PendingIntent.getService(// put here the intent)
then, whenever the notification is clicked, your service that have the thread will be executed from onStartCommand and all you need to do is:
cancel = getIntent.getBooleanExtra("cancel", false);
then inside the thread you must check for the boolean cancel from the service like this:
public MyService extend Service{
boolean cancel = false;
private Runnable myThread = new Runnable{
#Override
public void run(){
// ... here you're doing the job on the different thread
if(cancel)
return;
}
};
}
The correct way is stopping it from the inside. That means that you define inside a controller (for example, a boolean) that checks some additional event within your app that determines if your Thread has to still execute or not. This implies that you'll have to put your code within a loop with a Thead.sleep() object inside to not overkill your thread, or use a Handler inside with a postDelay() action inside, but that's the way.
If you don't want to use it, you can also declare a BroadcastReceiver inside. You register your receiver, and wait for some action you define (I recommend an own action so you don't interfere with Android's) and once your receive event fires, just use return in your Thread so it exits.
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.