Android AlarmManager to continue after reboot / delete from RecentTaskManager

I would like to implement sending notifications to users from the server using AlarmManager at a time when the user previously set it. The code is as follows:

MainActivity:

public void set_Retrival_then_notifcation_Alarm(Context context, int year, int month, int day, int hour, int min, int sec) { Calendar updateTime = Calendar.getInstance(); updateTime.setTimeZone(TimeZone.getDefault()); updateTime.set(Calendar.YEAR, year); updateTime.set(Calendar.MONTH, month-1); updateTime.set(Calendar.DATE, day); updateTime.set(Calendar.HOUR_OF_DAY, hour); updateTime.set(Calendar.MINUTE, min); updateTime.set(Calendar.SECOND, sec); Intent downloader = new Intent(context, AlarmBroadcastReceiver.class); downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), pendingIntent); } 

ParseService:

 public class ParseService extends IntentService { static String Parse_AppID = "abc"; static String Parse_ClientKey = "abckey"; String notification_next_price = ""; String notification_next_date = ""; SharedPreferences settings; public class LocalBinder extends Binder { public ParseService getService() { return ParseService.this; } } public ParseService() { super("ParseService"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent,flags,startId); return START_STICKY ; } @Override protected void onHandleIntent(Intent intent) { Log.d("MyService", "About to execute MyTask"); new MyTask().execute(); } private class MyTask extends AsyncTask<String, Void, Boolean> { @Override protected Boolean doInBackground(String... strings) { Log.d("MyService - MyTask", "Calling doInBackground within MyTask"); initParse(ParseService.this); get_notification_info(ParseService.this); return false; } } private void sendNotification(Context context, String title, String content) { Log.d("MyService - MyTask", "A - sendNotification"); settings = context.getSharedPreferences("MyApp",0); boolean notify_is_on = settings.getBoolean("notify_is_on", true); int saved_amount = settings.getInt("saved_amount", 800); NumberFormat numberFormat = NumberFormat.getInstance(); int k = 0; try { k = numberFormat.parse(notification_next_price).intValue(); if (notify_is_on && (k >= (saved_amount*10000))) { setNotificationContent(context, k, ""+title, content + ""); } else { Toast.makeText(getApplicationContext(), "No need notification", Toast.LENGTH_SHORT).show(); } } catch (Exception ex) { setNotificationContent(context, k, "Title2", "Content2"); } } public void setNotificationContent(Context context, int k, String title, String content) { Intent notificationIntent = new Intent(context, CurrentResult.class); PendingIntent pi = PendingIntent.getActivity(context, 0, notificationIntent, 0); Notification noti = new Notification.Builder(context) .setTicker("Hello") .setSmallIcon(R.drawable.b06) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher)) .setAutoCancel(true) .setOngoing(true) .setOnlyAlertOnce(true) .setContentTitle(""+title) .setContentText(""+content) .setContentIntent(pi) .build(); startForeground(1337, noti); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, noti); stopSelf(); } @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } public void initParse(Context context) { try { ...connection to Parse.com } catch (Exception e) { e.printStackTrace(); } } public void get_notification_info(Context context) { ParseQuery<ParseObject> query = ParseQuery.getQuery("Record_db"); //....getting records from server sendNotification(ParseService.this, ""+notification_next_price, ""+notification_next_date); } } else { Toast.makeText(getApplicationContext(), "Getting server content error", Toast.LENGTH_SHORT).show(); } } }); } } 

AlarmBroadcastManager

 public class AlarmBroadcastReceiver extends BroadcastReceiver { public AlarmBroadcastReceiver () { } @Override public void onReceive(Context context, Intent intent) { Intent dailyUpdater = new Intent(context, ParseService.class); context.startService(dailyUpdater); Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive"); } } 

manifest:

 <service android:name="com.abc.abc.ParseService" android:enabled="true" android:exported="true" /> <receiver android:name="com.abc.abc.AlarmBroadcastReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> 

Question:

Retrieving records from the server and sending notifications work correctly when the application is on the list of recent tasks.

However, if the application is manually removed from the recent task list, the emergency manager and, therefore, the notification is canceled and the notification does not receive.

I have googled and most solutions should return START_STICKY in onStartCommand in order to register with Manifest, but I tried without success.

Could you help me figure out what the problem is? Why can’t the notification be restarted after the application is manually removed from the recent task list? Is there any example for this ParseService work for a user-specified time?

Thanks!

+5
source share
4 answers
  • You need to save logged alarms in local db
  • then create a finished download recipient
    • in this receiver loads all alarms and registers them again
  • in class AlarmBroadcastReceiver remove this alarm from db

thats it

+4
source

Instead of AlarmManager you should use GcmListenerService , this will even notify that your application has been removed from the task manager, GcmListenerService

+3
source

I changed

 set_Retrival_then_notifcation_Alarm 

for testing. Adding 30 seconds at the current time and setting an alarm. At the same time, kill the app from a recent test task.

  Calendar cur_cal = Calendar.getInstance(); cur_cal.setTimeInMillis(System.currentTimeMillis()); cur_cal.add(Calendar.SECOND, 30); Log.d("Testing", "Calender Set time:"+cur_cal.getTime()); Intent intent = new Intent(this, ParseService.class); Log.d("Testing", "Intent created"); PendingIntent pi = PendingIntent.getService(this, 0, intent, 0); AlarmManager alarm_manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); alarm_manager.set(AlarmManager.RTC, cur_cal.getTimeInMillis(), pi); Log.d("Testing", "alarm manager set"); Toast.makeText(this, "ServiceClass.onCreate()", Toast.LENGTH_LONG).show(); 

You can start the service from PendingIntent. This will solve the problem if the user clears the recent task from the application.

As indicated by Hossam Alaa on the page, you can do this for download. Also you do not need AsyncTask in IntentService. It has a workflow.

ParseService sample (change according to your needs, currently it will wait 5000 ms and trigger a notification).

 public class ParseService extends IntentService { public ParseService() { super("ParseService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { try { Thread.sleep(5000); setNotificationContent("HELLO","THERE"); //stopSelf(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void setNotificationContent( String title, String content) { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification noti = new Notification.Builder(this) .setTicker("Hello") .setAutoCancel(true) .setOngoing(true) .setSmallIcon(R.mipmap.ic_launcher) .setOnlyAlertOnce(true) .setContentTitle(""+title) .setContentText(""+content) .setContentIntent(pi).build(); startForeground(1337, noti); NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, noti); } } 
+2
source

Alarms are only removed if your application is deleted or disabled (in the application manager), they definitely survive after a normal reboot or suspension.

But I'm not sure that your manifest is configured correctly: An alarm sends a broadcast to "AlarmBroadcastReceiver.class" and it will respond if the application is at a specific point in time.

I suggest broadcasting a custom action with a warning and registering it in the receiver.

Add to the receiver in the manifest:

 <intent-filter> <action android:name="com.abc.abc.action.downloader" /> </intent-filter> 

And use a different intent for alarm, for example:

 Intent downloader = new Intent(context, "com.abc.abc.action.downloader"); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT); 
0
source

Source: https://habr.com/ru/post/1259778/


All Articles