I have relatively simple setup that should trigger an alarm at certain time of the day and show a notification to user. here is relative code,
Setting the alarm
long inTime = /*expirationTime*/ Calendar.getInstance().getTimeInMillis() + 10000;
Intent startIntent = new Intent("parking.event");
startIntent.setClass(getBaseContext(), ParkingExpirationWarmingBroadcast.class);
PendingIntent startPendingIntent = PendingIntent.getBroadcast(this, 99, startIntent, 0);
alarmMgr.setExact(AlarmManager.RTC_WAKEUP,
inTime,
startPendingIntent);
BroadcastReceiver registered
<receiver
android:name=".modules.parking.ParkingExpirationWarmingBroadcast"
android:enabled="true">
<intent-filter>
<action android:name="parking.event" />
</intent-filter>
</receiver>
Broadcast Receiver
class ParkingExpirationWarmingBroadcast : BroadcastReceiver() {
#SuppressLint("NewApi")
override fun onReceive(context: Context, intent: Intent) {
}
}
The receiver is only getting triggered if app is in background. as soon as i swipe the app from multitasking, the notification is cleared and no new Alarms are triggered. I checked this setup on Android 7.0 and BroadcastReceiver is triggered regardless of app running or not.
I am aware regarding restrictions over implicit broadcasts in Android Oreo but i don't believe the intent that i have mentioned above is considered implicit.
Can anyone point out what i am doing wrong?
This is a general behavior of any Android's version. If you force-quit an application, then its Alarms and PendingIntents are deleted as well.
You can find the same answer here and here.
Force closing an app destroys its components . This is what force stop does. It's not a bug, it is very much a feature. Follow the following thread , it has been discussed by android framework engineers .
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/anUoem0qrxU
Related
I have an app that should update/get data from a server every six hours. To do so I made an AlarmManager the following way:
public class Repository {
public static AlarmManager alarmManager;
public static void initAlarmManager(Context context){
//start the update alarm manager
Intent resultIntent = new Intent(context,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, 60 * 60 * 1000, pendingIntent);
}
My AlarmReceiver now has to look for updates and if there is new data of a specific condition it has to notify the user via a notification. This is a part of my AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(Repository.ddfDb == null){
Repository.initDdfDb(context);
}
if(Repository.alarmManager == null){
Repository.initAlarmManager(context);
}
for(Episode episode : Repository.ddfDb.getListOfNextEpisodes()){
Notification.showNotification(context,episode);
}
}
}
Since my AlarmManager should run all the time I let him start also when boot is completed. To do so I added the following to my manifest file:
<receiver android:name=".AlarmReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
I run the function initAlarmManager() in my onCreate() of the mainActivity. So if the app is started, the AlarmManager starts too and everything works fine. Even if I close my app via the home button or change to another app via the "change between recent apps" button, my AlarmManager still fires and I get the notifications although my app is in the background.
I also run the function initAlarmManager() in my AlarmReceiver. So if I reboot my phone, the receiver gets called, sees that my AlarmManager is null and inits it afterwards. So everything works fine here too.
But here is my problem: If I press the "change between recent apps" button and close my app with a swipe my AlarmManager stops and I won't get any further notifications. This is weird, since after a reboot my app also doesn't appear in the recent apps menu but there it works.
I googled a lot and some people say it is impossible, since if the user really wants to close the app, he has to be able to do so. I understand this, since it provides security against virus apps. But also I see apps like WhattsApp being able to always notify the user.
So is there really no way to accomplish my always running AlarmManager or if there is a way, how do I implement this?
Thank you in advance!
I solved this issue the following way:
I moved all operations I did in the BroadcastReceiver to an IntentService. All the BroadcastReceiver now does is starting this IntentService.
When the app is now closed by swiping it away from the recent apps menu, my notifications still pop up.
Thanks to Muthu for giving me the right hint!
This is how I am creating an alarm.
When the app is still running in background the alarm is fired.
but when it is cleared from the recent apps, the alarm is getting discarded. I am registering a new receiver and providing a unique action for differentiation between two alarms. Is there any mistake in my code.
String filter_action = "myPackageName" + request_code_value +"_time";
IntentFilter filter = new IntentFilter(filter_action);
registerReceiver(new AlarmReciever(), filter);
Intent intent = new Intent(filter_action);
intent.putExtra(getString(R.string.get_current_intent_value), request_code_value);
intent.putExtra(getString(R.string.alarmtext), alarm_title);
intent.putExtra(getString(R.string.alarm_time), newAlarm_Choose_Alarm_Value.getText().toString());
Calendar calNow = Calendar.getInstance();
Calendar calSet = (Calendar) calNow.clone();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, request_code_value, intent, 0);
calSet.setTimeInMillis(timeInMillis);
if (calSet.compareTo(calNow) <= 0) {
// Today Set time passed, count to tomorrow
calSet.add(Calendar.DATE, 1);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(), pendingIntent);
Manifest file.
<receiver android:name="com.bigbangpartners.YoWakeUp.activities.AlarmReciever" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="AlarmManager_Start" />
</intent-filter>
</receiver>
Please help me.
Thanks in advance.
If you are registering and de-registering the BroadcastReceiver programmatically in your Activitys, then a BroadcastReceiver created in this way will remain in existence only as long as the app process is alive. So when you remove your app from the list of recent apps, this BroadcastReceiver is also, in effect, destroyed.
On the other hand, a BroadcastReceiver registered in the manifest is a global, permanent component of an Android app that remains in existence forever, whether the app process is alive or not.
If you want your alarms to be activated even when the app is not in the foreground, then you need to register the BroadcastReceiver in the app manifest and specify the alarm action as well. You are not doing that, and this, I believe, is the root of your problem.
What you should do:
1. Define your BroadcastReceiver in manifest like this:
<receiver android:name="com.bigbangpartners.YoWakeUp.activities.AlarmReciever" >
</receiver>
2. Remove all calls to registerReceiver() and unRegisterReceiver() in your app code as that is not needed.
3. Define your alarm Intent like this:
Intent intent = new Intent(this, AlarmReceiver.class);
Rest of code remains same. First try this and see if it works.
Android. How to keep an application running after the system is going to kill it?
Or how not to let the system to kill it?
I need to support the application in the foreground. That is, open the app every 30 seconds, regardless of whether it is minimized or closed.
While the application is running (it is displayed in the list of cached) method is called OnReceive. If the application is unloaded from memory, it no longer triggers Activity
use AlarmManager, BroadcastReceiver
Activity1.OnCreate
...
Intent intent = new Intent(this, typeof(MyAppReciever));
PendingIntent sender = PendingIntent.GetBroadcast(this, 0, intent,PendingIntentFlags.UpdateCurrent);
AlarmManager am = (AlarmManager)GetSystemService(AlarmService);
am.SetRepeating(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime()+30000,30000,sender);
BroadcastReceiver
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionPowerConnected })]
public class MyAppReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent intent1 = new Intent(context, typeof(Activity1));
intent1.AddFlags(ActivityFlags.NewTask);
context.StartActivity(intent1);
}
}
manifest
....
<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name="AndroidApplicationTest.MyAppReciever">
<intent-filter>
<action android:name="android.intent.action.POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
</intent-filter>
</receiver>
UPD #1
Let's simplify the example. For example , I want the application to be opened periodically ( shows the current Activity). Procedure is as follows: run the application by double clicking on the icon , then minimize by home-button. The application appears in the "working apps" (in the cache ) . Begin to actively use the phone , my application is gradually replaced and disappears from the "working apps" Say an hour after the first run , I want the application to reopen the (initial Activity). I hope that AlarmManager rise OnReceive event in which spelled Activity open the main application.
what am I doing wrong?
Problem with your Pending Intent. Use same action and category to match your Receiver intent filter to wake up your Receiver.
Ultimately you cannot stop android from killing your activity. Any memory crisis comes up, there is no guaranty that your application will be running.Least priority given to a services running in background for not get killed. But with your Service.start_sticky your tell android that woke run background service and memory becomes available. So the service is only one android component that can you keep running for your application that is also with no guaranty.
I have an alarm to reset a data connection say every 15 minutes. The problem is, once the phone is rebooted, the application gets killed and the alarm (service) doesn't trigger anymore.
(This is not a duplicate, the other similar questions on SO do not solve my problem.)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.sang.mobiledata.ResetBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Broadcast Receiver:
public void onReceive(Context context, Intent intent) {
// if(CONN_ACTION.equals(intent.getAction())) {
if (intent.getAction().equalsIgnoreCase(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE")) {
MainActivity objMain = new MainActivity();
objNetwork.setMobileDataEnabled(context, false);
objNetwork.setMobileDataEnabled(context, true);
}
if (intent.getAction().equalsIgnoreCase(
"android.intent.action.BOOT_COMPLETED")) {
// code to restart/resume/retain alarm
Code to fire alarm (on the onClick):
Intent myIntent = new Intent(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE");
myIntent.putExtra("FLAG_KEY", false);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
long interval = intHrs * 3600000 + intMins * 60000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), interval, pi);
long mins = interval / 60000;
Toast.makeText(
MainActivity.this,
"Data Connection will be reset every " + mins
+ " minute(s).", Toast.LENGTH_SHORT).show();
}
Any suggestions please?
Read the AlarmManager document, there it is written, that AlarmManager will not hold alarms after reboot.
As per the Android Developers,
.... Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
And regarding BOOT_COMPLETED, they write:
... This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.
As for permission is concerned, you have already registered that. Well what probably happening is, the service BOOT_COMPLETED is being used locally, with the application. The reboot of the mobile is system activity, which is not overridden to accomplish re-registry of the alarms being saved. But I am not sure. So, you need to do something when execution comes in hand of BOOT_COMPLETED.
Read Automatically starting Services in Android after booting, this might help you with it.
What I did was, I registered all the alarms and formed a database, using SQLite; On restart, I use to reset all the alarms. Well that worked for me. If you want to go with my process then,
Make a database for your alarms, and save them there. Write your application in such a way that, when the phone restarts, the AlarmManager resets all the alarms. This is how it works.
In Automatically starting Services in Android After booting again. It is written:
Also note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.
Code that schedules alarm.
PendingIntent sender = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, time, sender);
Its working fine, but when I kill my app in task killer, I lost my scheduleed alarm. How to solve this problem?
have your application broadcast a message as its being killed, and when this message is broadcast, then have a listener check if the service is still running.. if its not run it. This will insure that your service is running even if the application is killed.
Update
I'll try to create a flow diagram for you
The onDestroy() method is part of a service.
I hope this helps.
UPDATE 2
One thing I forgot to mention is the fact that you ideally only want one instance of the service to be run. So just looking at the ID that is present within the onStart() should be == to 1 to start it else.. ignore it.
Methods of notice of the Service Class:
onStart() : This method is called when the service is being started
onDestroy() : This is the method that is called when a service is being killed
Methods of notice of the BroadcastReciever class:
onReceive(): This methods receives all intents that are sent to it (unless filtered)
Look up examples on BroadcastRecievers (Message Broadcasting) and Service (Starting a service)
References:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
http://developer.android.com/reference/android/app/Service.html
Alarm set by alarm manager is not killed when app is closed, how ever when a reboot occurs all alarms are cleared by the os since there is no persistence. So you need to do the persistence.
Every Time while setting a alarm save the alarm time.
Register a receiver for boot completion.
Set the alarm again on reboot.
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//re register the alarm
}
}
Manifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
.......
<receiver
android:name="BootReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
You could use SharedPreference to save the time (time at when the alarm should be triggered or time at when it should be triggered next)
Use that to set a new alarm at the boot receiver.