I've been stuck on this for days now.
I want my alarm manager to fire off every 15 minutes even when the app is closed but it does not work when app is closed. It works while app is open though.
In my manifest file I have:
<!-- Used to consume the alarm manager alerts when app clsoed -->
<receiver
android:name="biz.customName.pkg.AlarmReceiver"
android:enabled="true">
<intent-filter>
<action android:name="biz.customName.pkg.msg"/>
</intent-filter>
</receiver>
My BroadcastReceiver class (AlarmReceiver)
public class AlarmReceiver extends BroadcastReceiver
{
// Alarm manager used to run install when app is closed
AlarmManager alarmManager;
// Called when alarm received
#Override
public void onReceive(Context context, Intent intent)
{
// Enable alarm
setupAlarm(context);
// Perform background task
}
// Setup alarm
public void setupAlarm(Context context)
{
// Setup reciever for alarm
// context.registerReceiver(this, new IntentFilter("biz.customName.pkg.msg"));
// Setup pending intent
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Loader.filterName), PendingIntent.FLAG_UPDATE_CURRENT);
// Setup alarm
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final long triggerTime = System.currentTimeMillis() + 900 * 1000;
// Newest OS
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 23)
{
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
}
}
}
In main I call setup alarm to get the alarm going initially then each time the onReceive inside my Broadcast receiver is called I reset the alarm.
What am I doing wrong that it doesn't work when the app is closed?
Add this in your AndroidManifest.xml
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".MyAlarmReceiver"
android:enabled="true"
android:exported="true" />
MyAlarmReceiver.java
public class MyAlarmReceiver extends BroadcastReceiver {
Context context;
public MyAlarmReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
intent = new Intent(context, MyService.class);
context.startService(intent);
}
}
MyService.java
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
YourTask();
return Service.START_STICKY;
}
private void YourTask(){
// call api in background
// send push notification
//etc...
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
PendingIntent pendingIntent;
AlarmManager alarmManager;
Intent alarmIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoUpdateDataInBackground();
}
private void AutoUpdateDataInBackground() {
// Retrieve a PendingIntent that will perform a broadcast
alarmIntent = new Intent(MainActivity.this, MyReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, alarmIntent, 0);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long interval = 15 * 60 * 1000;
// Repeating on every 15 minutes interval
Calendar calendar = Calendar.getInstance();
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),interval, pendingIntent);
}
}
BTW : AlarmManager will not be called with locked screen and enabled energy saving mode
Related
I want to show local notification on specific time. So that I am using alarm manager to set pending intent for specific time. But in my case Broadcast/Service is not getting called if application killed by user.
Check the below code and help me out why am not getting notification after application killed.
public class MainActivity extends AppCompatActivity {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent notifyIntent = new Intent(this,MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(MainActivity.this, 1, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+30000, pendingIntent);
}
}
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MyNewIntentService.class);
context.startService(intent1);
}
}
public class MyNewIntentService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
CommonUtil.showNotification(getApplicationContext());
return START_STICKY;
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false"
/>
<service
android:name=".MyNewIntentService"
android:exported="false"
/>
You can check here for working sample of Alarm with Broadcast receiver.
How to use Android AlarmManager in Fragment in Kotlin?
I'm currently working with Android Alarm Manager and found a working example. But it does not work properly in my situation. Let me explain. Basically my goal is to execute a method from the MainActivity each 5 mins. For this purpose I use Alarm Manager to schedule that task.
Basically this is the working stuff:
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("SERVICE_TEMPORARY_STOPPED"));
}
}
MainActivity.java
public class MainActivity extends Activity{
private PendingIntent pendingIntent;
private AlarmManager manager;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I'm running", Toast.LENGTH_SHORT).show();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
registerReceiver(broadcastReceiver, new IntentFilter("SERVICE_TEMPORARY_STOPPED"));
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startAlarm();
}
});
}
public void startAlarm() {
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 300000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Log.d(TAG, "Alarm Set");
}
}
Everything is good. "I'm running" Toast is executed every 300000 ms (5 mins). The AlarmReceiver class send a broadcast to my main Activity with the message "SERVICE_TEMPORARY_STOPPED". I already registered that message in my MainActivity via registerReceiver(broadcastReceiver, new IntentFilter("SERVICE_TEMPORARY_STOPPED"));. But, when I add another method, let's say stopAlarm() in the broadcastReceiver, which is going to stop the alarm after 5 mins, the time interval (5 mins) is not applied anymore. In something like 10 secs, it calls the Broadcast Receiver and stop the alarm. And this is the issue. Take a look at the stop() method and how I call it on the broadcastReceiver:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I'm running", Toast.LENGTH_SHORT).show();
stopAlarm();
}
};
public void stopAlarm() {
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
Log.d(TAG, "Alarm Cancelled");
}
Any clue?
AlarmManager.setRepeating doesn't work properly on different android versions.
Try setExact. It won't repeat but you can achieve repeating functionality as mentioned below:
Updated AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("SERVICE_TEMPORARY_STOPPED"));
long repeatCount = PreferenceManager.getDefaultSharedPreferences(context).getLong("REPEAT_COUNT", 0L);
repeatCount++;
PreferenceManager.getDefaultSharedPreferences (context).edit().putLong("REPEAT_COUNT", repeatCount).apply()
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
manager.setExact(AlarmManager.RTC_WAKEUP, (repeatCount *System.currentTimeMillis()),pendingIntent);
}
}
Here we maintain a repeatCount & variable (preference based) and increment it in your AlarmReceiver & schedule alarm again by calculating nextAlarmTime using repeatCount * System.currentTimeMillis();
How do I implement a periodic Task that queries the db and deletes row periodically? I want to do this so that I prevent my database from growing too big over time.
Using a Sticky Service with AlarmManager and BroadcastReceiver is what you need.
public class MY_SERVICE extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// remove last alarm you set
Intent intent = new Intent(context, MY_DB_PROCEDURE_BROADCAST.class);
intent.setAction("myDbProcedure");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context,1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.cancel(alarmIntent);
// add new alarm manager
intent = new Intent(context, MY_DB_PROCEDURE_BROADCAST.class);
intent.setAction("myDbProcedure");
alarmIntent = PendingIntent.getBroadcast(ct, 1, intent, 0);
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(),
intervalMin*60*1000, alarmIntent);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
your BroadcastReceiver class :
public class MY_DB_PROCEDURE_BROADCAST extends BroadcastReceiver {
private final String TAG=getClass().getName();
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG,"Started");
// DO YOUR DB TASK HERE
}
}
In your manifest define the service and broadcastReceiver:
<service
android:name="MY_SERVICE"
android:enabled="true"
android:exported="true" />
<receiver android:name="MY_DB_PROCEDURE_BROADCAST" android:enabled="true"/>
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 am trying to set up an alarm that will run in the background and trigger (eventually) a save event. At the moment I simply have this code attached to a button. Press the button and the alarm should start leaving Toast messages behind as an indication that it is functioning. At the moment everything runs except the onReceive in the BroadcastReceiver is never triggered.
Here is my code:
The class setting up the alarm:
//FIXME - rename (ie BackgroundSave; more descriptive)
public class AlarmReceiver extends Service{
//FIXME - make sure you kill the service
public void onCreate() {
super.onCreate();
Toast.makeText(getApplication().getApplicationContext(), "Service onCreate called", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getApplication().getApplicationContext(), "Service started", Toast.LENGTH_SHORT).show();
setAlarm(AlarmReceiver.this);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
public void setAlarm(Context c) {
AlarmManager alarmManager = (AlarmManager)c.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(c, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, i, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMillis() + 1000, 1000, pi);
Toast.makeText(c.getApplicationContext(), "setAlarm called", Toast.LENGTH_SHORT).show();
}
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);
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
Here is the BroadcastReceiver:
public class Alarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm", Toast.LENGTH_SHORT).show();
}
}
And here is my manifest:
<!-- Alarm -->
<service android:name="com.xxxx.android.tools.AlarmReceiver" android:enabled="true" />
<receiver android:name="com.xxxx.android.tools.Alarm" ></receiver>
The alarm onReceive is never triggered.
You have to use android.os.SystemClock.elapsedRealtime() as your base time when using AlarmManager.ELAPSED_REALTIME_WAKEUP.
That said i think to use the AlarmManager for your saving purpose is not the best approach. The alarm manager is pretty heavyweight. You should consider using a simple Handler to trigger your save action.
Have a look at Handler.postAtTime().