I have following code in intent service (I have to use intentservice)
//TIME HANDLER
Log.i("start", "start getting data acc & gps");
//Register listeners and start getting data
//
// ACC:
onStartAcc();
//
handle_lower.postDelayed(new Runnable() {
#Override
public void run() {
Log.i("stop getting data", "STOP");
//Stop listeners
//
// ACC:
onStopAcc();
//==========================================================================
//HERE IS CALCULATING STATUS
//
status.calculateState();
//==========================================================================
}
}, Constants.TIME_ACCELEROMETER_GETTING);
and it doesn't call runnable, no log is shown and accelerometer receiver is not unregistered.
I don't know why this happens. Can someone help me?
I have to use intentservice
You have to not use IntentService for this use case.
it doesn't call runnable, no log is shown and accelerometer receiver is not unregistered
Once onHandleIntent() returns, the IntentService shuts down and goes away. Therefore, you cannot register listeners, fork threads, use poorly-implemented timing systems, etc. in an IntentService.
You are welcome to use a Service. Convert your postDelayed() stuff into a ScheduledExecutorService (so your work is done on a background thread), and make sure that you call stopSelf() at the appropriate point to shut down the service.
Related
I get the current location in my app using requestLocationUpdates but in case it takes too long to detect I use a timer to cancel the operation.
For your information I tell you I do all this process in a WakefulBroadcastReceiver so the device should NOT sleep until either a position is received or the time out happens. Once one of those happens I call to completeWakefulIntent to let the device sleep again.
Everything works great but sometimes the timer never finishes and no location is got, either. I guess my process is maybe killed or destroyed by the system.
So, is there a way to ensure the timer to execute after an amount of time?
Any help would be appreciated
Check AlarmManager.
Schedule a non repeating alarm once the location finding activity is fired.
This alarm in turn fires your killer activity that cancels the location finding activity, after an appropriate amount of time
Or use Handler. Something like:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do something
// this executes after 2000 milliseconds
}
}, 2000);
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).
Also if this BroadcastReceiver was launched through a <receiver> tag, then the object is no longer alive after returning from onReceive(). This means you should not perform any operations that return a result to you asynchronously.
Please see the documentation for BroadcastReceiver
Cheers!
Use Timer.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
//This will execute afteer every 1 Minute
}
}, 0, 60000);
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.
I am using AlarmManager of Android and scheduling a repeating alarm using elapsed_time_wakeup for every minute. This alarm fires of a service.
Service does its work (pinging the server(Facebook server in my case) to get data). Next I call onDestroy() of the service. So every minute Service starts -> Does work -> onDestroy()
Is the best way to do this in android?
Do you really need new service every minute? I think you want to start single service. That service does each minute check on server and reports success or error somehow? You want simple always running service with periodic action, not periodic service starting. In this case, starting new service would consume maybe more resources than check itself.
Just make sure service stays running. That might be case until you call stopSelf() from it and starting activity does not stop it also. You may want to run it as
private ping() {
// periodic action here.
scheduleNext();
}
private scheduleNext() {
mHandler.postDelayed(new Runnable() {
public void run() { ping(); }
}, 60000);
}
int onStartCommand(Intent intent, int x, int y) {
mHandler = new android.os.Handler();
ping();
return STICKY;
}
You might want periodic check only on Wifi connection or connection present. And maybe to stop checking when you already know about problem and are solving it. You may want to use startForeground() from Service to start some activity to control it and display results.
One of my activity periodically updates nearby friends, which location is obtained from rest service
Currently I use postDelay:
private Runnable updateNearbyFriendsTask = new Runnable() {
#Override
public void run() {
list = api.getNearby(.....)
handler.postDelayed(this, UPDATE_RATE);
}
};
The problem is that postDelayed executed on UI thread, so this runnable task block ui with poor internet connection.
What is the right way to make periodic background rest requests from activity? I don't want to create service for that, because this rest method is used only in this activity.
EDIT
Currently switched to using ScheduledExecutor
this.scheduledExecutor.scheduleWithFixedDelay(new UpdateNearbyFriendsTask(), 0, UPDATE_RATE, TimeUnit.MILLISECONDS);
private class UpdateNearbyFriendsTask implements Runnable() {
#Override
public void run() {
list = api.getNearby(.....)
runOnUiThread(.....)
}
};
I don't see what the problem is with creating a Service, even if it is only used for this activity.
That being said, have a look at the TimerTask. It seems to do what you want.
How about BroadCast receiver using Alarm manager.. http://developer.android.com/reference/android/app/AlarmManager.html
Since its a long running and on going task, would you want to write a Service or an Intent service which does the background job for you.
You can just ping the service whenever your time ticks and let the service do the network activity, freeing up the UI thread for something else. you can always query the service to know the status, or the service itself can respond back to your UI thread.
For ticking the timer, you can use the alarm manager, or perhaps something else (I am not good at any :P )
I'm trying to create a service that runs in a given interval. The service's purpose is to update a database and when done notify an Activity with an Intent.
The service should also be callable from the activity when the user chooses to 'refresh'.
I have accomplished this, but I can't get it to run in a detached thread.
The service executes an update method in a Runnable:
private Runnable refresh = new Runnable() {
public void run() {
update(); //Runs updates
didUpdate(); //Sends broadcast
handler.postDelayed(this, 50000); // 50 seconds, calls itself in 50 secs
}
};
I have another runnable called ManualRefresh that is called via a broadcast from the activity.
However these runnables seem to be blocking the UI.
Need advice! :)
When you run a Runnable by calling it's run method, it runs on the current thread. To run on a background thread, you need to use new Thread(refresh).start(); (if the Runnable you want run is refresh).
You can also make use of AsyncTask for this, but that's more appropriate for an activity than for a Service. Information about using AsyncTask can be found in the API docs and in the article Painless Threading.
I suggest to write the service using the AlarmManager. The service will receive an Intent to tell it to periodically to update the database.
Once updated, you can notify the Activity with an Intent (as you mentioned).
When the user wants to manually refresh, have the Application sent an Intent to you service. Receiving the Intent from the AlarmManager or from the Activity would perform the same code.
You may also want to reschedule the alarm after a request to manually refresh.