Strange issue, my app has tens of thousands of users, for most of them this works perfectly. Some, let's say 5%, experience issue that causes reminders to not be fired.
I've put logging on the scheduling mechanism, including the scheduled timestamp, so I know that the reminder was scheduled, but it AlarmReceiver wasn't called.
Why would AlarmManager sometimes not fire?
ReminderLogic.java -
public class ReminderLogic {
public static void schedule() {
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
int timeMillis = ... // some calculation
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeMillis, alarmIntent);
else
alarmManager.set(AlarmManager.RTC_WAKEUP, timeMillis, alarmIntent);
}
}
AlarmReceiver.java -
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, AlarmService.class);
startWakefulService(context, service);
}
}
AlarmService.java -
public class AlarmService extends IntentService {
private final static String TAG = "AlarmService";
public AlarmService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
ReminderLogic.schedule();
AlarmReceiver.completeWakefulIntent(intent);
}
}
BootReceiver.java -
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ReminderLogic.schedule();
}
}
PackageReplaceReceiver.java -
public class PackageReplaceReceiver extends BroadcastReceiver {
private static final String TAG = "BootReceiver";
#Override
public void onReceive(Context context, Intent intent) {
ReminderLogic.schedule();
}
}
AndroidManifest.xml -
<service android:name=".reminders.AlarmService" />
<receiver android:name=".reminders.AlarmReceiver" />
<receiver
android:name=".reminders.BootReceiver"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name=".reminders.PackageReplaceReceiver"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
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 am using the following code to start a service periodically whether the app is foreground or not .
Intent getAlertIntent = new Intent(getApplicationContext(), GetAlertAlarmReceiver.class);
PendingIntent getAlertpendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, getAlertIntent, 0);
AlarmManager getAlertmanager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
getAlertmanager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10000, getAlertpendingIntent);
The code for my receiver is following
public class GetAlertAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, GetAlertServiceIntent.class);
context.startService(i);
}
}
And and service
public class GetAlertServiceIntent extends IntentService {
public GetAlertServiceIntent() {
super("GetAlertServiceIntent");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(Intent intent) {
doSomething();
}
}
In my manifest file I declared everything as following
<receiver
android:name=".broadcastreceiver.GetAlertAlarmReceiver"
android:enabled="true">
<intent-filter android:priority="999">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name="com.surroundapps.shotorkoporibar.services.GetAlertServiceIntent" />
This code work as expected in API level below Marshmallow but in marshmallow it doesn't work .
I have an Activity that is supposed to launch a Service via a BroadcastReceiver.
Overview of the three:
Activity = Tracking
Service = PhoneManagementService
BroadcastReceiver = TrackingRestart
The Activity launches the AlarmManager in the onCreate() method:
public class Tracking extends Activity {
private static final int ALARM_FREQUENCY_SECONDS = 60;
#Override
protected void onCreate(Bundle savedInstanceState) {
startService(new Intent(Tracking.this, PhoneManagementService.class));
Intent alarm = new Intent(this, TrackingRestart.class);
boolean alarmRunning = (PendingIntent.getBroadcast(this, 0, alarm, PendingIntent.FLAG_NO_CREATE) != null);
if(!alarmRunning) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarm, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), (ALARM_FREQUENCY_SECONDS * 1000), pendingIntent);
}
}
I included startService(new Intent(Tracking.this, PhoneManagementService.class)); in there because this is the only time that the Service is called.
The BroadcastReceiver looks like this:
public class TrackingRestart extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, PhoneManagementService.class));
context.stopService(new Intent(context, PhoneManagementService.class));
}
}
The Service class looks like this:
public class PhoneManagementService extends Service {
private String user = "Service";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
startForeground(NotificationCreator.getNotificationId(), NotificationCreator.getNotification(this));
DBAdapter newEntry = new DBAdapter(this);
newEntry.open();
newEntry.addEntry("charging", user, getChargerType());
newEntry.addEntry("battery", user, getBatteryStats());
newEntry.addEntry("network", user, getNetworkType());
newEntry.close();
}
}
The Manifest containts those three entries:
<activity android:name=".Tracking">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".GPSService"
android:process=":trackingService_gps"
android:launchMode="singleTop"
android:enabled="true" />
<service
android:name=".PhoneManagementService"
android:process=":trackingService_phoneManagement"
android:launchMode="singleTop"
android:enabled="true" />
<receiver
android:name=".TrackingRestart"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="ch.jpabig.jonastrackingapp.ActivityRecognition.RestartTracking"/>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
<action android:name="android.intent.action.BATTERY_LOW"/>
<action android:name="android.intent.action.BATTERY_OKAY"/>
</intent-filter>
</receiver>
Somehow the entries into the database are not made and I'm at a lost why this is the case. It must be the alarm but I could be very wrong.
I can't seem these to get up and running:
public class BackgroundSyncService extends IntentService {
public BackgroundSyncService() {
super("SchedulingService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i("asd-service", "lol");
BackgroundSyncBroadcastReceiver.completeWakefulIntent(intent);
}
}
Second class:
public class BackgroundSyncBroadcastReceiver extends WakefulBroadcastReceiver {
private AlarmManager alarmManager;
private PendingIntent alarmIntent;
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, BackgroundSyncService.class);
startWakefulService(context, service);
}
public void setAlarm(Context context){
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, BackgroundSyncBroadcastReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
0, 5000, alarmIntent);
ComponentName receiver = new ComponentName(context, BackgroundSyncBroadcastReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
}
Third class:
public class BackgroundSyncBootReceiver extends BroadcastReceiver {
BackgroundSyncBroadcastReceiver service = new BackgroundSyncBroadcastReceiver();
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
service.setAlarm(context);
}
}
}
Manifest.xml:
<receiver android:name=".BackgroundSyncBroadcastReceiver"/>
<receiver android:name=".BackgroundSyncBootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<service android:name=".BackgroundSyncService"/>
Your receiver for BOOT_COMPLETED will not be allowed to fire until your app has been manually started by the user one time. This is a security feature to prevent apps from running without the user knowing about them.
So, yeah, I forgot to start it from the acivity...
BackgroundSyncBroadcastReceiver service = new BackgroundSyncBroadcastReceiver();
service.setAlarm(this);
Stupid mistake.
I have an AlarmReceiver with an AlarmService and my problem is, if I set the AlertDate about 30min away from the current time, it just does it's job and calls the Alert-function. But if I set it about 5hours away, it won't call the function, no matter if I do it at night (not using my phone) or at day (while my phone is in use).
So my question is, why can't I set the AlertDate in the "far" future? Is the process killed or is there anything strange happening? And in particular: How can I fix this problem??
Basically I have the arrangement from here: Android Alarm Clock Tutorial
So I just point out my main lines in the code:
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="apm.smoothalert" >
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
...
<application
...
<activity
android:name=".main"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".AlarmService"
android:enabled="true" />
<receiver android:name=".AlarmReceiver" />
</application>
main:
public class main extends ActionBarActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
PowerManager powman = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powman.newWakeLock(PowerManager.FULL_WAKE_LOCK,"MyWakelockTag");
wakeLock.acquire();
...
}
AlarmManager alarmManager;
private PendingIntent pendingIntent;
private void smoothAlertOn ()
{
Date AlertDate = ... ; //Here I select the Alert date with a Timepicker
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(main.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(main.this, 0, myIntent, 0);
alarmManager.set(AlarmManager.RTC, AlertDate.getTime(), pendingIntent);
}
public static void SmoothAlert(final Context context)
{
//Here i do the Alert with Notifications etc.
}
}
AlarmReceiver:
public class AlarmReceiver extends WakefulBroadcastReceiver
{
static Context Alarmcontext;
#Override
public void onReceive(final Context context, Intent intent)
{
Alarmcontext = context;
ComponentName comp = new ComponentName(context.getPackageName(),AlarmService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
AlarmService:
public class AlarmService extends IntentService
{
public AlarmService()
{
super("AlarmService");
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onHandleIntent(Intent intent)
{
main.SmoothAlert(AlarmReceiver.Alarmcontext);
}
}