I have a service that autoupdates a database in a given time interval. To do this it gets information from the Internet.
I need to have it unbound, so that It runs over all activities. But when the application is closed, it would be nice to terminate the service. To prevent battery drain. How can this be achieved?
I think that you should let your service be started by a boot broadcastReceiver, then ask AlarmManager to relaunch it every now and then.
public class DbUpdateService extends Service {
//compat to support older devices
#Override
public void onStart(Intent intent, int startId) {
onStartCommand(intent, 0, startId);
}
#Override
public int onStartCommand (Intent intent, int flags, int startId){
//your method to update the database
UpdateTheDatabaseOnceNow();
//reschedule me to check again tomorrow
Intent serviceIntent = new Intent(DbUpdateService.this,DbUpdateService.class);
PendingIntent restartServiceIntent = PendingIntent.getService(DbUpdateService.this, 0, serviceIntent,0);
AlarmManager alarms = (AlarmManager)getSystemService(ALARM_SERVICE);
// cancel previous alarm
alarms.cancel(restartServiceIntent);
// schedule alarm for today + 1 day
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
// schedule the alarm
alarms.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), restartServiceIntent);
return Service.START_STICKY;
}
}
To start your service at boot time use this :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class serviceAutoLauncher extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context,DbUpdateService.class);
context.startService(serviceIntent);
}
}
Finally add this to your manifest to schedule your serviceAutoLauncher to be launched at each boot:
<receiver android:name="serviceAutoLauncher">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
<category android:name="android.intent.category.HOME"></category>
</intent-filter>
</receiver>
Use the stopService method.
It depends on how you start the service. If you start it when your Activity is opened, then call stopService in your Activities onDestroy().
Related
My alarm is killed when OS kills the app. I thought that was one of the points of an Alarm, that it would keep running even though OS killed the app? I check the life of the Alarm using the "./adb shell dumpsys alarm" command, and every time OS kills my app, the Alarm is also gone. How I start my Alarm:
public static void startLocationAlarm(Context context){
if(ActivityLifecycleHandler.isApplicationInForeground()) {
return; // If App is in foreground do not start alarm!
}
String alarm = Context.ALARM_SERVICE;
AlarmManager am = ( AlarmManager ) context.getSystemService( alarm );
Intent intent = new Intent(locationBroadcastAction);
PendingIntent pi = PendingIntent.getBroadcast( context.getApplicationContext(), 0, intent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = ONE_MINUTE;
long triggerTime = SystemClock.elapsedRealtime() + interval;
am.setRepeating(type, triggerTime, ONE_MINUTE, pi );
}
To add some more context, I am trying do some location operation in a service (not IntentService) in background. Here is my receiver. Used Wakeful because I did not want the service to be killed before it was done.
public class LocationBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent ) {
Intent myIntent = new Intent( context, LocationServiceAlarmOwnGoogleClient.class );
//context.startW( myIntent );
LocationBroadcastReceiver.startWakefulService(context, myIntent);
}
}
For some more information: I cancel the alarm in OnStart method of several activities that the user can return to after having it in the background. I do not know if that can cause this weird behaviour? Here is my cancel method:
public static void stopLocationAlarm(Context context){
Intent intent = new Intent(locationBroadcastAction);
PendingIntent sender = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
You can add service which listens to the phone's turning on callback.
add this permission into the manifest
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and register reciever
<receiver android:name=".util.notification.local.MyBootCompletedService">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
public class MyBootCompletedService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
AlarmReceiver.startLocalNotificationService(context);
}
}
The error that caused the Alarm to be canceled had actually nothing to do with the code, but had to do with special battery settings on Huawei devices. If your app is not set as "protected" in "protected apps", the system will cancel your alarm when it kills the app. Adding your app to "protected apps" will solve this problem. Same goes for Xiaomi devices. Have to add them to "Protected apps", then the Alarm will work as intended. Thank you #CommonsWare for leading me to the solution.
I am making an application with a feature of alarms in it. I am using service for this which keeps checking the current time of device against the times in my DB.
My problem is that this service stops if the app removed from the background or if the device is rebooted. I have used START_STICKY to keep it running in background and used a broadcast receiver to start it on reboot.
The major concern is that whatever I have coded is working on a MOTO G device. Reboot, clearing from background, everything, the service is running fine. But in Xiomi phones and Huawei Honour, It stops once cleared from background or rebooted.
The Service code:
public class RemindService extends Service {
final long delayMillis=500;
Handler h=null;
Runnable r;
SharedPreferences sp;
PendingIntent pendingIntent;
private static final int NOTIFY_ME_ID=1337;
#Override
public void onCreate() {
h=new Handler(Looper.getMainLooper());
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags,int startId) {
r = new Runnable() {
public void run() {
//SOME OF MY IF-ELSE CONDITIONS
Intent myIntent = new Intent(RemindService.this, ReminderPopUp.class);
int randomPIN = (int)(Math.random()*9000)+1000;
pendingIntent = PendingIntent.getActivity(RemindService.this, randomPIN, myIntent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC|AlarmManager.RTC_WAKEUP, System.currentTimeMillis() , pendingIntent);
h.postDelayed(this, delayMillis);
}
};
h.post(r);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
h.removeCallbacks(r);
}
}
My Manifest declarations:
<service
android:name="test.aguai.medieazy.RemindService"
android:enabled="true" />
<intent-filter>
<action android:name="test.aguai.medieazy.START_SERVICE" />
</intent-filter>
Has anybody else faced this problem? I think it is a problem of modified OS, but anyways my app is not working properly. Please Help.
Rather than poll the device database constantly, I would make use of the AlarmManager service as I described in this answer:
Android Polling from a Server periodically
Set up the alarm to fire at the first scheduled time. When it fires, set up the next time and so on. There is no need to set up every alarm at once as only one can ever fire at a time.
When the alarm fires, you can start a service to perform whatever task you need (including the setting of the next alarm)
Try Lik this it will Work
// for Every 6 minutes exact repeating service
Intent myIntent2 = new Intent(sign_in.this,MyAlarmService.class);
pendingintent3 = PendingIntent.getService(sign_in.this, 2,myIntent2, 2);
AlarmManager alarmManager2 = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(System.currentTimeMillis());
calendar2.add(Calendar.SECOND, 30);
alarmManager2.set(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), pendingintent3);
alarmManager2.setRepeating(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), 360 * 1000,pendingintent3);
manifest permission
<!-- Web data Sync Service -->
<service android:name="com.example.MyAlarmService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</service>
If you want your service to be running until explicitly stopped then consider calling startService(), to start the service. This allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().
Remember you must explicitly stop the service, by calling stopSelf() or stopService().
I am calling a Alarm from a service ScheduleAdvanceBookingService to call another service SendRequestAdvanceBookingService at a predetermined time.
Manifest file has
<service
android:name=".ScheduleAdvanceBookingService"
android:enabled="true"
android:label="#string/app_name" />
<service
android:name=".SendRequestAdvanceBookingService"
android:enabled="true"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.NOTIFY" />
</intent-filter>
</service>
My calling code has
public class ScheduleAdvanceBookingService extends IntentService {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newIntent = new Intent(this,
SendRequestAdvanceBookingService.class);
Date startTime = (Date) intent.getSerializableExtra("startTime");
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.setAction("android.intent.action.NOTIFY");
autoBookingAlarm = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
autoBookingPendingIntent = PendingIntent.getService(this, 0, newIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
long alarmCallTime = cal.getTimeInMillis();
autoBookingAlarm.set(AlarmManager.RTC_WAKEUP, alarmCallTime,
autoBookingPendingIntent);
Log.d("Taxeeta", "Scheduled a Auto Advance Booking #"
+ cal.getTime().toLocaleString());
My future alarm'ed Service is
public class SendRequestAdvanceBookingService extends Service {
public SendRequestAdvanceBookingService() {
super();
handler = new Handler();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Taxeeta", "Start - SEND REQUEST.");
Debug statement to check the date
08-20 13:40:14.008: D/Taxeeta(31578): Scheduled a Auto Advance Booking #20 Aug 2014 13:41:37
What am I missing here ?
I have tried
Removing the intent-fiter and the addAction, still wont fire
Using startTime directly instead of using cal.setTime(startTime) cal.getTimeInMilli()
The fix was simple and non documented anywhere.
I ran ./adb shell dumpsys alarm > ~/dump.txt and searched for my alarms on my device. I found many pending alarms on the device for my app. This prompted me to clean up, and a Force Close from Settings->Application->MyApp->Force Close, cleaned up the alarms.
Then I ran my app, and it worked. Only after a while I realized that phones that did not have the app running earlier worked well, and that hinted me to the cleanup again.
So all I needed to do was
autoBookingAlarm.cancle(autoBookingPendingIntent);
before the
autoBookingAlarm.set(AlarmManager.RTC_WAKEUP, alarmCallTime,
autoBookingPendingIntent);
This will cancel previous alarms before scheduling a new one.
Currently i can only send the data to the server when my app (activity) is in foreground. This happens at least in 4.1.3 because the android SO pauses the app or stops it.
I need to send data all the time even if the activity is in background.
What is the best way of achieving this. Asynctask is not a good answer because i want to send data periodically. Not once. I already use asynctasks as a way to send the data to the server what i need is something that runs together with the activity but doesn't get stopped by the SO.
EDIT:
I got this error using the below code.
04-03 13:55:28.804: E/AndroidRuntime(1165): java.lang.RuntimeException: Unable to instantiate receiver main.inSituApp.BootCompletedIntentReceiver: java.lang.ClassNotFoundException: main.inSituApp.BootCompletedIntentReceiver
Can anyone tell me what that error means? i dont have a class with that receiver but i though if i register it in the manifest i wouldn't need it.
You can write services and AlarmManager to do so. Simply register your application in services and call alarmMangaer.setRepeat() method to start your code of serverside or any other operation you want to do in onStart() method of services
public class MyService extends Service{
Calendar cur_cal = Calendar.getInstance();
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(getApplicationContext(),
0, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
cur_cal.setTimeInMillis(System.currentTimeMillis());
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cur_cal.getTimeInMillis(),
60 * 1000*3, pintent);
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
// your code for background process
}
}
Add this in AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service
android:name="com.yourpackage.MyService"
android:enabled="true" />
<receiver android:name=".BootCompletedIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Edit:
BootCompletedIntentReceiver.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootCompletedIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context, MyService.class);
context.startService(pushIntent);
}
}
}
Excuse me, I have a question please.
I want to create a service to start once the the device is up and running by extending BroadcastReceiver. Inside the service class, I want to initiate an alarm manager to display a notification after certain time. Then, once the time is elapsed the notification is displayed, the alarm manger should be rescheduled for the next specified time. How could achieve that as alarm manager set function requires pending intent where no pending intent is required as I am inside a service class. I insist on using alarm manager instead of Timer as the following link suggests using it: Which is better for a background service WakeLock or startForeground
The code:
public class BootCompletedReceiver extends BroadcastReceiver {
final static String TAG = "BootCompletedReceiver";
#Override
public void onReceive(Context context, Intent arg1) {
Log.w(TAG, "starting service...");
context.startService(new Intent(context, BookkeeperService.class));
}
}
import android.app.AlarmManager;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
public class BookkeeperService extends Service {
AlarmManager alarmManager;
#Override
public void onCreate(){
super.onCreate();
alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
// here I need to set the alarm to notify the user after certain time and then reschedule
// to the next event
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Thank you
If you want to pass messages through a Alarm to Broadcast Reciever, just have the Alarm dispatch a message at your leisure and then have that start your registration for more alarm(s). You can start the Alarm from your service and from there have the Alarms maintain themselves.