Android, sleep a service - android

I'm implementing an app on Android. I've just added a new service that is called on boot-completed. This service creates a new thread that is simply a loop, making something minute after minute. To wait the next minute I used Thread.sleep(60000) but it doesn't work: after the waiting period no other action is performed. It seems that the app is closed or waiting permanentely.
Is there another way to make a loop-service avoiding Thread.sleep? I don't think it is a problem of code because if I call the main method of the service on the app starting it works (it is a problem related to the service)
Thank you in advance
I think the problem is related to the "scan media" of my LG L9 II.. when the "scan media" (I think is about my sd card) is completed all my service are killed (or something like it). Any suggestion?

Consider using AlarmManager to invoke your service. Below example illustrates how to establish repeating events every minute from AlarmManager.
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getBaseContext(), AlarmReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(getBaseContext(), 0, intent, 0);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), ONE_MINUTE, pending);

Services don't have their own thread, the share the main (UI) thread. If you want to do something every minute, create a new thread and have it do something once a minute.

There is almost never a good reason to use Thread.sleep(...) or explicitly create threads in Android. If you need something to happen every 60 seconds, create a Handler and use its postDelayed(...) methods. You can post a task that will re-post itself each time it runs. Just make sure you cancel it when your app is shutting down.

Related

Android: which kind of Broadcast/Receiver combination should I use?

In my app, I want to kick off an timer that triggers an action every x minutes, regardless if the user is currently in the app or not. I have been reading around and am not sure which combo of Broadcast and Receiver types I should use - any guidance would be helpful.
Example of user actions:
User hits a button, sets initial timer (alarm)
Timer is reached, trigger an action and set the timer again
Repeat until it has run for x minutes
when the user hits button set alarm as
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
am.setRepeating (AlarmManager.Type,
long triggeringtime,
long interval,
PendingIntent operation);
here triggeringtime is how to time it shud take to take an action
and interval how to much time it would take to do the same.
here operation is the Intent which you need to execute like it may be an activity or Service you can Define it as
operation = PendingIntent.getActivity( context, 0, intent or service, 0);
2 and 3 step will be continuously run thats what the alarm manager does.
This alarm continues repeating until explicitly removed with
cancel(AlarmManager.OnAlarmListener).
I am a beginner Sry if i wrong. Hope it helps!
Android JobScheduler
You can find a lot of tutorial online.

Correct way to do polling in Android app

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.

Starting new Alarm from service started by AlarmManager

In my app i am using AlarmManagerto start service every week on a specific time. But in some cases instead of waiting another 7 days I need to call the service on the next day. Because of that I'm not using reapeating alarm but instead in the started service I'm creating new Alarm and set it to a specific date. Something like this:
public class AlarmService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//do something
//setting new alarm
AlarmManager alarmMng = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this,AlarmService.class);
PendingIntent alarmIntent = PendingIntent.getService(this, 0, i, 0);
Calendar c = Calendar.getInstance();
if(something) alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24,alarmIntent);
else alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24*7,alarmIntent);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
Everything works fine but I wonder if this is good way to do it. Is it a good idea to create new alarm from service that was just called by one? Is it considered bad programming practice? If so how else should I handle it?
Is it considered bad programming practice?
No - this is a fine use case for creating alarm events. If you look at the documentation, use of AlarmManager is intended to send events to your app even if it is not running. Receiving those events in a Service that then schedules another alarm event is perfectly fine. The rest of my answer is intended to explain how to answer the other question you ask:
Is it a good idea to create new alarm from service that was just
called by one?
To determine if you need a Service really depends on the "do something" portion of your code more than setting the alarm. For example, you might be fine using a IntentService or even a BroadcastReceiver.
EDIT:
In other words, you will need a background process to handle this. Determining the appropriate background process (Receiver or Service) depends on how much processing needs to be done. Generally, setting an alarm all by itself could probably be handled in a Receiver but if it takes too long to process (e.g. more than 10 seconds) you will get an ANR (Application Not Responding) crash. That's when you need a service.
END EDIT..
This is a good post about services: Service vs IntentService
Specifically, the concern you should have is if your service is called multiple times, you should probably include code to cancel any previous alarms created by it, before setting a new alarm.
EDIT: Also, you are not "creating a new service" or "new alarm" each time. Services will have onStartCommand called each time an intent is sent to it (by the AlarmManager or by any other means). A new instance is not created unless it is not already instantiated.

Do i need to use broadcast with alarm manager?

i'm creating an alarm application, and this is the method to run the alarm :
public void startAlarm(int minuteToStart)
{
Toast.makeText(context, "Alarm Start in " + formatTime(minuteToStart), Toast.LENGTH_SHORT).show();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, minuteToStart);
Intent intent = new Intent(context, AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, idPendingIntent, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
And it run this activity after given specific time:
public class AlarmActivity extends Activity {
......
}
It works, but i see people are using BroadcastReceiver, am i doing it wrong? should i use BroadcastReceiver too? I've been searching about BroadcastReceiver but i don't get what difference it will make with my application.
Thanks.
In the general case, A--C's answer would be correct.
However, you are using RTC_WAKEUP as the alarm type. The only guarantee that we have with _WAKEUP alarms is if we use a BroadcastReceiver, then Android will ensure that the device will stay awake long enough for us to execute onReceive(). Any other type of PendingIntent -- activity or service -- has no guarantee, and it is very possible for the device to fall back asleep before the startActivity() or startService() actually occurs.
You can use AlarmManager with whatever PendingIntent is capable of (Activity, service, Receiver), though, it is usually used with Receivers - taks executing in the future usually are small and don't need an Activity to run in since the user doesn't need something popping up.
A Receiver isn't an Activity, so it does not have a UI and it has a processing time limit of about 10 seconds, so make sure to be quick. If you require a UI to be shown at a specific time, stick with an Activity, but usually this isn't the case unless it's something like an Alarm Clock app that the user has to see). If you have something like a small behind the scenes operation, go for a Receiver. The Receiver's onReceive() gets a Context passed to it so it can do anything a Context can.
Just keep in mind you will have to change the PendingIntent.getActivity() call to whatever else you decide to use if it's not going to be an Activity.
So it all depends on what you want to do.
You don't have to use a BroadcastReceiver. It's just generally frowned upon (in most cases) to steal focus and launch an Activity from the background without user interaction. There are certainly valid use cases though. If you intend to launch an Activity immediately anyway, doing that directly instead of via BroadcastReceiver is perfectly valid.

How to set a timed event which will keep running even if the application is stopped

I need to have a process run whenever the end-user clicks on a Submit button. The application needs to try to process the data on the screen every X minutes, Y times, even if the the application is down. So, it will need to attempt to do some processing until one of the following occurs:
1) The processing is successful for the data that was submitted
2) The processing has been retried Y times and still never succeeded
3) The application is terminated by the OS or the phone is turned off.
If the end-user's phone is still on but the application has stopped,
what's the correct interface to use to accomplish this?
If I use Handler/Runnable, that only works as long as the application stays active.
AlarmManager looks like it's used when you want processing to run at a specific time.
Any suggestions will be greatly appreciated!
I use this method to set an alarm.
private void setAlarm(){
Context context = getApplicationContext();
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
myCal = Calendar.getInstance();
myCal.setTimeInMillis(myPrefs.getLong("time", 0));
mgr.set(AlarmManager.RTC_WAKEUP, myCal.getTimeInMillis(), pi);
Log.i(myTag, "alarm set for " + myCal.getTime().toLocaleString());
Toast.makeText(getApplicationContext(),"Alarm set for " + myCal.getTime().toLocaleString(), Toast.LENGTH_LONG).show();
}
inside my onAlarmReciever onRecieve method is this:
Intent i = new Intent(context, AlarmActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
So basically when the intent fires it starts the AlarmActivity. Inside that activity you could have it try what ever you are doing and if it fails call the setAlarm() again
You have two options: a Service, or set up an alarm with AlarmManager. Which one you pick will depend mostly how often do you want to retry. A minute? Use a service. An hour? A day? set up an alarm so you don't waste the phone resources keeping the service alive.
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/reference/android/app/AlarmManager.html
Write an Android Service

Categories

Resources