I'm attempting to start up a Background IntentService that will run every minute. I want to start this Service after the user logs into my app for the first time, so I have my code here:
This code will only be called after the user logs in:
public class MainMenuActivity extends SingleFragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
// This is reached after logging in, so we are setting alarm on login
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isOn = prefs.getBoolean(GPSTracker.PREF_IS_ALARM_ON, false);
GPSTracker.setServiceAlarm(this, true);// TODO: Always setting this to true, not sure if we should be
}
Then I have this code in my GPSTracker which extends IntentService:
private static final int POLL_INTERVAL = 1000 * 60 * 1;// 1 minute
public static void setServiceAlarm(Context context, boolean isOn) {
Intent i = new Intent(context, GPSTracker.class);
PendingIntent pi = PendingIntent.getService(context, 0, i, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if(isOn) {
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, System.currentTimeMillis(), POLL_INTERVAL, pi);// TODO: Is AlarmManager.ELAPSED_REALTIME what I want!?
} else {
alarmManager.cancel(pi);
pi.cancel();
}
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(GPSTracker.PREF_IS_ALARM_ON, isOn).commit();
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "In onHandleIntent");
}
However, my onHandleIntent is never called, and I never see anything in LogCat.
You are using AlarmManager.ELAPSED_REALTIME with System.currentTimeMillis(). That is an invalid combination.
Either:
Use AlarmManager.RTC with System.currentTimeMillis(), or
Use AlarmManager.ELAPSED_REALTIME with SystemClock.elapsedRealtime()
Related
I want to trigger a one-time alarm with the following, which is basically a replicate from https://developer.android.com/training/scheduling/alarms.html (second ELAPSED_REALTIME_WAKEUP example).
This is inside public static class PlaceholderFragment extends Fragment implements View.OnClickListener:
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(this.getActivity(), MuteReceiver.class);
AlarmManager alm = (AlarmManager)(this.getActivity().getSystemService(Context.ALARM_SERVICE));
PendingIntent alarmIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
alm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 60*1000,
alarmIntent);
Log.d("MainActivity", "alarm set");
}
public class MuteReceiver extends BroadcastReceiver is like this:
public MuteReceiver() {
Log.d("MuteReceiver", "constructed");
}
#Override
public void onReceive(Context context, Intent intent) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean started = prefs.getBoolean(MuteService.STARTED, false);
Log.d("MuteReceiver", "Started=" + started);
}
I pressed the button in the Fragment, saw the log message "alarm set", but after one minute (and much later), still no log about MuteReceiver being constructed or MuteReceiver started (in onReceive)
You have a guaranteed list file with a registered broadcast
In android (as a beginner) I have created an AlarmService class to act as a service, i.e. to run every fixed interval in the background, to check data and probably to notify the user that something is going on.
The AlarmService class is defined as follows:
public class AlarmService extends Service
{
Alarm alarm = new Alarm(this);
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
alarm.SetAlarm(this);
return START_STICKY;
}
#Override
public void onStart(Intent intent, int startId)
{
alarm.SetAlarm(this);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
and the actual Alarm is implemented as follows:
public class Alarm extends BroadcastReceiver
{
private Context mContext;
public final static String LOGHEAD = "StoxxAlarm";
public Alarm() {
mContext = null;
}
public Alarm(Context context) {
mContext = context;
}
#Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);
int updateInterval = Integer.parseInt(sharedPref.getString("updateInterval", "24")); // ##PROBLEM##
// ... do something here
}
public void SetAlarm(Context context)
{
// get the update cylce from the prefences
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);
int updateInterval = Integer.parseInt(sharedPref.getString("updateInterval", "24"));
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 60 * updateInterval, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
The problem occurs in the line marked with ##PROBLEM## as the context is null. How can I fix the problem?
The funny thing is, that I fixed something else in the code which did not work. Before that fix (related to something else), this kind of worked. But now, how to make sure the function becomes a proper 'context' (what ever this is, I still do not understand properly what a context is...).
How can I fix the problem?
With respect to this specific concern, mContext will always be null, because Android will not use your one-parameter constructor when it sends you a broadcast. Get rid of mContext, and use the Context that is passed into onReceive().
Beyond that:
I do not know why you are returning START_STICKY
I do not know why you are overriding onStart() and onStartCommand(), given that onStart() was deprecated 6-7 years ago
I do not know why you have SetAlarm() and ClearAlarm() as methods on Alarm, forcing you to create an Alarm and then throw it away, instead of having those methods be implemented on the service, or have them be implemented as static methods somewhere
You are using RTC_WAKEUP, which is fine, but unless the work you plan to do is sub-millisecond in duration, you really need to use the WakefulBroadcastReceiver pattern, so you do not tie up the app's main application thread in onReceive() and also can keep the device awake
instead of mContext, you should use context
I am trying to create a background service that will be called every ten minutes, perform a task and this should not be killed when the application is closed.
The following is the code snippet:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_service);
Intent intent = new Intent(this, AlarmReceiverLifeLog.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
alarms.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 10 * 60 * 1000, pendingIntent);
}
In onCreate, it will call the AlarmReceiverLifeLog class every ten minutes. The following is the code for AlarmReceiverLifeLog class:
public class AlarmReceiverLifeLog extends BroadcastReceiver {
static Context context;
#Override
public void onReceive(Context context, Intent intent) {
Intent ll24Service = new Intent(context, LifeLogService.class);
context.startService(ll24Service);
}
}
public class LifeLogService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartService = new Intent(getApplicationContext(), this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(getApplicationContext(), 1, restartService, PendingIntent.FLAG_ONE_SHOT);
Calendar calendar = Calendar.getInstance();
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, calendar.getTimeInMillis() + 100, restartServicePI);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I am not able to figure out what I have missed. When I close the app the background services is getting killed.
Can anyone suggest anything regarding this?
when the app is closed the service get closed also because they are in a one thread, so the service should be on another thread in order fot it not to be closed, look into that and look into keeping the service alive with alarm manager here an example http://www.vogella.com/articles/AndroidServices/article.html this way your service won't be shown in notification.
I want to implement a Service which permit to show a notification (daily, or after XX minutes) even if I close the application. (Actually, when I press back button, I finish the MainActivity...)
I need a runnable notification even if I didn't start the application (after rebooting the device for example, of course when the trigger is declanched)...
I tried some clear examples and tutorials but I doesn't find what I need.
Please HELP!
Thanks in advance,
Mohamed
You can do it with alarm manger:
public class AlarmHelper {
private Context context;
private AlarmManager alarmManager;
private static final String TAG = "AlarmHelper";
public final static String ALARM_ALERT_ACTION = "com.android.alarmclock.ALARM_ALERT";
public AlarmHelper(Context context) {
this.context = context;
alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
}
public void setNotifyAlarm(Long milliSecond) {
PendingIntent pendingIntent = getNotifyPendingIntent();
alarmManager.cancel(pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, milliSecond, pendingIntent);
// alarmManager.set(AlarmManager.RTC_WAKEUP, milliSecond, sender);
}
public void cancelNotifyAlarm() {
PendingIntent pendingIntent = getNotifyPendingIntent();
alarmManager.cancel(pendingIntent);
}
private PendingIntent getNotifyPendingIntent() {
Intent intent = new Intent(context, AlarmExpireService.class);
return PendingIntent.getService(context, 0, intent, 0);
}
public void setExpireAlarm(int minute) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, minute - 1);
PendingIntent pendingIntent = getExpirePendingIntent();
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
pendingIntent);
}
public void cancelExpireAlarm() {
PendingIntent pendingIntent = getExpirePendingIntent();
alarmManager.cancel(pendingIntent);
}
private PendingIntent getExpirePendingIntent() {
return PendingIntent.getService(context, 0, new Intent(context,
AlarmExpireService.class), 0);
}
}
Now in the AlarmExpireService.java:
public class AlarmExpireService extends Service {
// private static final String TAG = "AlarmExpireService";
private static final String TAG = "AlarmExpireService";
#Override
public void onCreate() {
super.onCreate();
//your logic for start activity or generate notification.
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
AppLog.Log(TAG, "On start command");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Now Register service in the manifest file:
<service android:name="your_package.AlarmExpireService" />
For just call a method from AlarmHelper's setNotifyAlarm method and your work is done pass the time in millisecond (it will start after that time and notification will be pop up).
For more information take a reference of this links:
1. AlarmManager
2. Service
3.Pending Intent
I'm trying to create a service that increments some variables every 10 seconds permanently. To do so, i used setInexactRepeating to launch it in onCreate of MainActivity, but the service is never created...
public class MainActivity extends Activity {
Mothership mothership;
AlarmManager manager;
Calendar calendar;
Intent i;
PendingIntent pIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mothership = (Mothership) getApplicationContext();
mothership.initTopBar((ImageView) findViewById(R.id.exposure_eye),(TextView) findViewById(R.id.energy_level), (TextView) findViewById(R.id.human_number));
mothership.data.changeCurrentActivity(DynamicData.Main);
manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
i = new Intent(MainActivity.this, TimerService.class);
pIntent = PendingIntent.getService(this, 0, i, 0); // paramètres à analyser
calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 10);
// Service
manager.cancel(pIntent);
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, calendar.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES/90, pIntent);
}
TimerService only contains 2 instructions in order the variables when it's called :
public class TimerService extends IntentService {
private final static String TAG = "TimerService";
Mothership mothership;
public TimerService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
incEnergy();
decStealth();
}
#Override
public void onCreate() {
super.onCreate();
mothership = (Mothership) getApplicationContext();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void incEnergy() {
mothership.data.energyInc();
mothership.topbar.update();
}
public void decStealth() {
mothership.data.exposureDecrease();
mothership.topbar.update();
}
}
What am I doing wrong?
I've empirically found that for both inexact and exact (pre-19 when all become inexact) repeating alarms, the minimum time seems to be about 30 minutes. Even then, I've found the timing for repeating alarms to be wildly unpredictable. For instance, when I've asked for a 35 minute period, I'll get some alarms at about 35 minutes intervals, some hours apart, and some within a few minutes of each other.
I've found it much more predictable to just ask for a one-shot alarm and then resubmit a new one each time the alarm fires.