I 'm writing a backgroud app only can use service.
I'use BroadcastReceiver start service. Sometimes it works well, but some sometimes it doesn't work.
I know the reason is BroadcastReceiver exec liftcycle is 10 seconds, so use it start a long time task will not be end.
Intent i = new Intent();
i.setClass(context, RegisterService.class);
context.startService(i);
What should I do if I want to execute a long time task only use BroadcastReceiver and service?
Make sure your service is not executing on the main thread. Consider using an IntentService, it does the right thing out of the box.
Related
I have to develop a simple application that every 5 seconds fetch a json from a server. I know that this will drain the battery but since I don't have control on the server, this is the only solution I have at the moment, so stay with me. (It's a demo app, the final release will be totally different)
What I did:
I created an IntentService and in his onHandleIntent I do the http request and manage the response asynchronously. Reading the docs, the IntentService is preferred to the Service. At the end, as seen in other topics, I use the AlarmManager class to recreate the intentService. That's the method:
private void repeat() {
lastTrigger = System.currentTimeMillis();
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent serviceIntent = new Intent(this, StatusPollingService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, lastTrigger + UPDATE_INTERVAL, pendingIntent);
}
In my onCreate in my first Activity, I simply start the service:
serviceIntent = new Intent(BaseActivity.this, StatusPollingService.class);
startService(serviceIntent);
My issues:
When I close my application (using back button), the intentService continues to do the requests and recreates itself (as expected), so I have to kill it manually
I'd like to stop to do polling every time my app goes in background and restart when goes in foreground, to limit the battery drain
My other issues:
I implemented a class that triggers a listener when the app goes in background/foreground. I implemented the interface in my BaseActivity and in my IntentService. When the app goes in background, a boolean became false and I don't execute the repeat() method. When I go in foreground, in my method onBecameForeground I simply create the service:
serviceIntent = new Intent(BaseActivity.this, StatusPollingService.class);
#Override
public void onBecameForeground() {
startService(serviceIntent);
}
Going in background there's no problem, but going in foreground multiple intentService are created, one intentService per every Activity I have in that moment (I see it in the log).
My questions:
Is this the best way to do this job? How could I resolve these problems?
If this is the best (or the less bad) way, how can I create a single instance of the IntentService?
Thank you so much for your help
If you only need it in the foreground, then I'd not bother with the alarms. Just post intents every 5 seconds to your intent service using Handler.
Supposedly there should be only one instance of the intent service, so if you post multiple intents for processing, they will get queued and handleIntent will be called in your intent service for each intent. Note that, however, that if your service is processing intents fast enough, then it may finish (and destroyed) before you post another intent - so you'll see multiple instances of the service being created. But there will only be one instance at a time.
Edit: to expand a bit, you will need the alarms when (and if) you'll be polling the server in background, so don't through that code away ;) Handler will keep "freezing up" in background as the OS doesn't count the time while the device was sleeping for the Handler postponed execution.
i have an IntentService that calls webservice in OnHandleIntent every 45 seconds using TimerTask.
my question is:
i am calling on app start the IntentService, and in OnHandleIntent the task keeps repeating due to TimerTask..is it a good practice to do this or does this have any drawbacks? should i use an alarm manager in my activity to call the intent service every amount of time or its fine to keep on repeaing the task in OnHandleIntent using the timer task?
my code is like this:
#Override
protected void onHandleIntent(Intent intent)
{
context=this; //INTENT CONTEXT
final int timerValue = Integer.parseInt(MainActivitySharedPref.GetValue(context, "serviceTimer"));
Log.d(TAG, "DOWNLOADSERVICE called having MainActivity.callService as: " + MainActivity.callService);
t = new Timer();
task = new TimerTask()
{
public void run() {
//run tasks
};
t.scheduleAtFixedRate(task, 0, timerValue); // service executes task every 45 seconds
Thank you.
Is it a good practice to use TimerTask in OnHandleIntent in IntentService?
Absolutely not.
IntentService is designed to allow you to perform work in a supplied background thread via onHandleIntent(). It is not designed for you to fork threads, register listeners, set up TimerTask/ScheduledExecutorService, or do anything else that would be running past the end of onHandleIntent(). The IntentService will shut itself down once onHandleIntent() ends, after which Android may terminate your process within seconds, before your background threads (or, in this case, TimerTask) can do its work.
Please use a regular Service.
should i use an alarm manager in my activity to call the intent service every amount of time or its fine to keep on repeaing the task in OnHandleIntent using the timer task?
If you are doing this only while some activity of yours is in the foreground, the every-45-seconds part is OK. If you are trying to do this continuously, on battery-powered devices, be prepared to be attacked by users for the battery drain that you are causing.
But, while an activity of yours is in the foreground... ScheduledExecutorService (the modern replacement for TimerTask) in a regular Service should be fine. You should not need AlarmManager, which is specifically designed to give you control after your process has been terminated, for longer polling periods.
I start a timer in activity1. And in the timer task, I run some code continuously for a long time. Then I sometimes need to start activity2 like below.
Intent intent = new Intent();
intent.setClass(Tomato.this, History.class);
startActivity(intent);
But then error occurs:
FATAL EXCEPTION: timer-1
Could anyone help?
Further:
I tested again, and found that this error didn't occur every time. Now I cannot even repeat it.
Thanks for all of you!
"I run some code continuously for a long time"
This is usually when you decide that this code should run in a service. Check out the Service SDK documentation and you'll get an example of local Service.
If the timer is just something you need to access accross activities, you could implement a singleton that will hold one instance of it.
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.
I am implementing a Service that starts when Android boots, and it's supposed to scan every 10 mins for nearby Bluetooth devices. When it discovers devices, it does some work. Also, this periodic scanning should occur the entire time the device is on. I am trying to schedule a TimerTask, but I don't understand how to use it. I guess it should start this service and let the service do the work instead of writing the code in the TimerTask's run method? How would I start the service from the TimerTask as this seems the easiest way to remedy my problem, but TimerTask is part of java.util and not one of Android's classes.
I just found Android's AlarmManager. Should I use that? Can it start a Service?
So far I have this, but I need help:
class Timer extends Service
{
private Handler myHander;
Runnable r = new Runnable()
{
run()
{
startService(new Intent(Timer.this.getApplicationContext() ,MyService.class));
myHandler.postDelayed(r,10 minutes);
}
}
onCreate()
{
myHandler=new MyHandler();
}
onStartCommand()
{
//Do the bluetooth work.
r.run();
}
onDestroy()
{
super.onDestroy();
myHandler.removeCallback(r);
}
}
class MyService extends Service
{
}
Sorry, I don't understand how the formatting works here.
Will I need to override onDestroy() in the Service? Where to do I use stopService() ?
You need to:
Write service that will be started from one of your activities and/or after device has booted.
In your service in onStart/onStartCommand you need to schedule either using Handler or AlaramManager periodic updates.
The difference between Handler and AlarmManager in this case will be that: Handler will not run when device is in deep sleep, while you can configure AlaramManager to wake up the device and run your code.
I'd recommend to go with Handler, as its easier and because you said you only need to run your code when device is awake.
And one more thing, Handler doesn't use extra thread while TimerTask does. And this is considered a bad practice on Android to waste on thread for timer only.
An example code for how to repeat task using Handler can be found here: Repeat a task with a time delay?.