Android: Scheduling application to start with repeating alarms not working - android

I get my Broadcast receiver to set a recurring alarm, to fire up a service. Unfortunately this does not result in the service being called repeatedly (based on logcat). I've experimented with different values for the time interval too. Can someone help? (I'm testing through Eclipse on Android 3.2 Motorola xoom)
Below is the code for the Broadcast receiver.
alarm = (AlarmManager) arg0.getSystemService(Context.ALARM_SERVICE);
Intent intentUploadService = new Intent (arg0, com.vikramdhunta.UploaderService.class);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 3);
PendingIntent pi = PendingIntent.getBroadcast(arg0, 0, intentUploadService , 0);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 5, pi);
Below is the code for the Service class
public UploaderService()
{
super("UploaderService");
mycounterid = globalcounter++;
}
#Override
protected void onHandleIntent(Intent intent) {
synchronized(this)
{
try
{
for (int i = 1;i < 5;i++)
{
// doesn't do much right now.. but this should appear in logcat
Log.i(TAG,"OK " + globalcounter++ + " uploading..." + System.currentTimeMillis());
}
}
catch(Exception e)
{
}
}
}
#Override
public void onCreate() {
super.onCreate();
Log.d("TAG", "Service created.");
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i(TAG, "Starting upload service..." + mycounterid);
return super.onStartCommand(intent,flags,startId);
}

Ok Looks like I got this one. Two changes were needed -
1 - i made a mistake of using PendingIntent.getBroadcast when I needed to do getService instead (hell, who knew!)
2 - In getService, I should have supplied PendingIntent.FLAG_UPDATE_CURRENT in the end instead of 0. FLAG_ONE_SHOT did not work. I guess since the interval is only 5 seconds, this is the right way.
Now I get the right service/function to be called every 5 seconds. Hurray!

Related

Callback listener when application is killed from recent applications in android

Let me come straight to my issue.
There is an old similar question:
Continue Service even if application is cleared from Recent app. Please go through the link before going ahead.
I have to save some data to the local database before the application is destroyed completely.
I have following issues with onTaskRemoved() method of the service:
onTaskRemoved() method is not triggered every time the application(and hence the service) is stopped from the recent applications screen.
Even if onTaskRemoved() is called every time, the method is not executed completely. I mean if there are 20 statements in the method, only 5 or 10 statements are executed and the method breaks after that. Like if I have 20 System.out.println() statements than only 5 or 10 or 12(any random number) statement prints and method breaks after that.
So I can rely on the method onTaskRemoved() method for cleaning up resources acquired by the application.
This is a blocking issue for my application release. I have tried every trick. Like having at least one activity in the stack(I am calling it GhostActivity) so that if the application is killed from the recent applications screen, we can do clean up in onDestroyed() method the activity. onDestroyed() is called but it has exact same issues like onTaskRemoved() method.
I am stuck on the issue since weeks and it's very annoying. Please let me know if anyone has any solution.
I finally myself got it worked. I used a combination of service and alarm manager. Every-time I want to handle the force close scenario, I start a service in which I run an infinite loop. This loop will iterator every 15 secs. In the loop, I set an alarm 20 secs from the current time. Now if the next iteration of the loop happens the alarm is updated and reset to 20 secs after new current time. In this way, the alarm will trigger only if the service was not destroyed by the user by calling stopService() method.
public class MyIntentService extends IntentService {
public MyIntentService() {
super("My IntentService");
}
private boolean stopped = false;
private Thread runningThread;
private static MyIntentService mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = MyIntentService.this;
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent intent) {
stopped = false;
runningThread = Thread.currentThread();
while(!this.stopped) {
Intent intent = new Intent("Your_Custom_Broadcast_Action");
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent broadcastIntent = PendingIntent.getBroadcast(WifiService.this, CLEAN_UP_ALARM_REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 20000, broadcastIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 20000, broadcastIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 20000, broadcastIntent);
}
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
mInstance = null;
if (runningThread != null) {
runningThread.interrupt();
}
}
public void stopService() {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent broadcastIntent = PendingIntent.getBroadcast(WifiService.this, CLEAN_UP_ALARM_REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(broadcastIntent);
stopped = true;
if (runningThread != null)
runningThread.interrupt();
}
public static MyIntentService getActiveInstance() {
return mInstance;
}
}

Android kill service when app relauch and close?

I have to run a task in background when reach the scheduled time.i assigned the task of waking up my service to Alarm Manager and it does well if the app is background/running.service keep running fine on app's background as well as foreground states if am not changing the state of app after beginning the service.for the purpose of well understanding the scenario's given below.
Case 1:
1.Setting up the schedule and sending the time to alarm manager and keep the app running.
2.Alarm manager calls the service when the time is reaching.
3.Service start running
4.when i close my app service get stopped
Case 2:
1.Setting up the schedule and sending the time to alarm manager and closing the app.now app in background.
2.Alarm manager calls the service when the time is reaching.
3.Service start running
4.Relaunching the app.service continuing running/working fine.
5.Now closing the app and the result is service dead.
I have to call the service only by Alarm Manager , not on every time when app launches for that purpose in service onStartCommand method i returned START_NOT_STICKY and i don't want to use START_STICKY.if i goes to START_STICKY it won't consider the scheduled time.and the thing is i don't want to check the time again as it's doing well by Alarm Manager.
When app running on low memory the services get destroyed.is the solution using startForeground instead of startService ?
How can i make my service running stable without bothering about the app opening/closing states ?
Setting schedule
public void setAction(View v) {
Calendar calendar = Calendar.getInstance();
int hour = Integer.parseInt(HH.getText().toString());
int minute = Integer.parseInt(MM.getText().toString());
int second = Integer.parseInt(SS.getText().toString());
String peried = PP.getText().toString();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.AM_PM, peried.equalsIgnoreCase("AM") ? Calendar.AM : Calendar.PM);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
myIntent.putExtra(ACTION,
ACTION_SC_1);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, REQUEST_CODE_SC_1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
}
Service class
public class MyService extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
final String action = intent.getStringExtra(ACTION);
final Handler handler = new Handler();
final Timer timer = new Timer();
final TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Toast.makeText(MyAlarmService.this, "Running....", Toast.LENGTH_LONG).show();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 1000, 5000); //execute in every 5000 msdo
// this.stopSelf();
} catch (Exception e) {
//TODO
}
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "Killed", Toast.LENGTH_LONG).show();
}
There are many ways to avoid killing of service...but we can not guarantee it. In low memory situations the service will be killed by the os. At this situation if you return START_STICKY this will restart the service with null intent. If you want the intent to be not null return START_REDELIVER_INTENT
See the android docs here

Service to create a notification everyday at a specified time

I want my app to show a notification with a "GOOD MORNING" message at 6 A.M everyday. As I read, for this I need the app to run in background so I need to use Service.
I have tried the following code but I'm stuck.
MainActivity.java
public void onClickStartService(View v)
{
startService(new Intent(this,MyService.class));
}
public void onClickStopService(View v)
{
stopService(new Intent(this,MyService.class));
}
and MyService.java is
public class MyService extends Service{
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
//Note: You can start a new thread and use it for long background processing from here.
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
}
I have buttons to start and stop the Service and it works. Now I want the service to create notification as I have mentioned at the beginning of the post. How can I do this?
To start the service at a specific time, I suggest you create a BroadcastReceiver triggered by an Alarm, which will in turn start your service.
First write a BroadcastReceiver like this :
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
context.startService(new Intent(context, MyService.class));
}
/**
* Schedule the next update
*
* #param context
* the current application context
*/
private static void scheduleServiceUpdates(final Context context) {
// create intent for our alarm receiver (or update it if it exists)
final Intent intent = new Intent(context, AlarmReceiver.class);
final PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// compute first call time 1 minute from now
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 10);
long trigger = calendar.getTimeInMillis();
// set delay between each call : 24 Hours
long delay = 24 * 60 * 60 * 1000;
// Set alarm
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, trigger, delay, pending);
// you can use RTC_WAKEUP instead of RTC to wake up the device
}
}
Then you just need to call the scheduleServiceUpdate method to start the reccuring event. If you only use the RTC type, then if the phone is locked when the alarm should trigger the service, it won't and will wait until the device is unlocked by the user. If you use RTC_Wakeup, the service will start exactly at the time given.
Note that there are other methods in the AlarmManager to trigger events.
You can start from PendingIntent and AlarmManager
Tutorial here
Dont forget to add possibility to cancel alarm manager with
mAlarmManager.cancel(pendingIntent);
Also you may want to intercept android.intent.action.BOOT_COMPLETED event to make you app starting immediately after reboot if you want to start your service by schedule.

AlarmManager.setRepeating - Service does not seem to repeat

I'm working on an Android app that sues a background task to fetch XML from a URL every x seconds (user defined interval, defaulting to 60). My structure is as so:
MainActivity
This schedules an Alarm via AlarmManager:
public static void scheduleAlarm(Context voContext, int viCheckInterval)
{
try {
moAlarmManager = (AlarmManager) voContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(voContext, AlarmReceiver.class);
moAlarmIntent = PendingIntent.getBroadcast(voContext, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, viCheckInterval);
moAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
time.getTimeInMillis(), moAlarmIntent);
} catch (Exception e) {
Log.e("MessageCheckAlarmHandler", e.toString());
}
}
AlarmReceiver
This is a BroadcastReceiver that starts the service:
#Override
public void onReceive(Context context, Intent intent)
{
Context oAppContext = context.getApplicationContext();
if (oAppContext == null) {
oAppContext = context;
}
Intent serviceIntent = new Intent(oAppContext, MessagingService.class);
oAppContext.startService(serviceIntent);
}
MessagingService
This creates our in-house logger (logging over TCP) and starts an AsyncTask called FetchPageTask:
public class MessagingService extends Service
{
#Override
public void onCreate()
{
super.onCreate();
...
this.acquireLocks();
try {
String sCheckerUrl = oPreferences.getString("pref_server", "");
int sCheckerPort = Integer.parseInt(oPreferences.getString("pref_server_port",
"8050"));
sCheckerUrl = String.format(URL, sCheckerUrl, sCheckerPort);
this.moFetchInboxTask = new FetchPageTask(this.logger, this);
this.moFetchInboxTask.execute(sCheckerUrl);
} finally {
this.releaseLocks();
this.stopSelf();
}
}
#Override
public void onDestroy()
{
super.onDestroy();
this.logger.close();
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
/**
* Acquire a WakeLock and a WifiLock.
*/
private void acquireLocks()
{
try {
// Acquire a wake lock to prevent the device from entering "deep sleep"
PowerManager oPowerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
this.moWakeLock = oPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
this.moWakeLock.acquire();
// Acquire a WiFi lock to ensure WiFi is enabled
WifiManager wm = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
this.moWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
this.moWifiLock.acquire();
} catch (Exception e) {
this.logger.error(TAG + "->onCreate()", "Error acquiring locks: " + e.toString());
}
}
/**
* Release our WakeLock and WifiLock.
*/
private void releaseLocks()
{
try {
this.moWakeLock.release();
this.moWifiLock.release();
} catch (Exception e) {
this.logger.error(TAG + "->releaseLocks()", e.toString());
}
}
}
FetchPageTask
This extends AsyncTask and does all the work of fetching the page and parsing the XML. It also then adds notifications and performs actions on the data retreived if need be.
This all works fine once, but does not run subsequently. I know that the AsyncTask works as I was previously doing it using pure Java via ScheduledExecutorService and ScheduledFuture and it worked. The only reason I decided to change to using AlarmManager is for maintainability purposes.
First, you are setting up your alarm to occur immediately, and then every ~43 years thereafter. That is unlikely to be what you want. Modify the third parameter of your call to setRepeating() to be the desired period in milliseconds, which right now is set to the number of milliseconds since midnight 1 January 1970.
Second, you are acquiring your WakeLock too late. There is no guarantee that your acquireLocks() will get a chance to run before the device falls asleep. My WakefulIntentService or the new WakefulBroadcastReceiver offer better patterns for passing control to an IntentService.
I think you don't need the Calendar here. You just want to run the action every x seconds, so It would be something like this:
moAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
viCheckInterval, moAlarmIntent);
// viCheckInterval should be long miliseconds

Android Service calling itself again 1 minute later

I'm trying to make a Service, wake up and call itself again after one minute (in this example, I know its bad for battery).
Here is part of the code:
public class SpeechService extends Service {
#Override
public void onCreate() {
super.onCreate();
setUpNextAlarm();
}
public void setUpNextAlarm(){
Intent intent = new Intent(SpeechService.this, this.getClass());
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
long currentTimeMillis = System.currentTimeMillis();
long nextUpdateTimeMillis = currentTimeMillis + 1 * DateUtils.MINUTE_IN_MILLIS;
// Schedule the alarm!
AlarmManager am = (AlarmManager)ContextManager.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,nextUpdateTimeMillis, pendingIntent);
Log.e("test","I am back!");
}
protected void onHandleIntent(Intent intent)
{
Log.e("test","I am back!");
setUpNextAlarm();
}
}
As you can see I'm calling setUpNextAlarm on service create, I see the log at the end, but then the service is never being called again. I have tried this in an IndentService, it works but I need it to work in a normal Service :(.
Thank you
Use
PendingIntent.getService
not
PendingIntent.getBroadcast
You are getting a Broadcast Intent.
I just ended up using a Service and an IntentService. The IntentService was using the AlarmManager and then it was calling the Service.

Categories

Resources