In my app, I use AlarmManager to start IntentService that accesses internal database of quotes and selects one randomly, then fires a notification with that quote.
It is working perfectly on my phone which is Android 9, OnePlus6. But I receive lots of crashlytics data from other users stating:
Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.myapp.receiver.AlarmReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.myapp/.service.NotificationQuoteService }: app is in background uid UidRecord{e3c2e3d u0a203 TRNB idle procs:1 proclist:23491, seq(0,0,0)}
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3606)
at android.app.ActivityThread.access$1300(ActivityThread.java:237)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1796)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7045)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
I presume, it is being caused from the restriction that Oreo has, that every background task should notify itself via foreground notification. However, wouldn't it be absurd to show foreground notification to query quotes and then show a quote notification?! There are lots of apps out there that do similar thing, they query internal data and show it in the notification without showing any foreground notification while data is being queried.
How would I do it, can someone point me in the right direction?
EDIT Codes are added:
AlarmManager to go off at 9 A.M. in the morning.
private void prepareAlarmManager() {
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, AlarmReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
if (alarmManager != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24 * 60 * 60 * 1000, pendingIntent);
}
}
BroadcastReceiver to handle AlarmManager
public class AlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 10;
@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, NotificationQuoteService.class);
context.startService(serviceIntent);
}
}
IntentService to query internal SQLite database and fire notification
public class NotificationQuoteService extends IntentService {
private Context mContext;
private DatabaseHelper mDatabaseHelper;
public NotificationQuoteService() {
super("quote service");
}
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
mDatabaseHelper = DatabaseHelper.getInstance(mContext);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
List<Quote> quoteList = mDatabaseHelper.getAllQuotes();
int size = quoteList.size();
int randomIndex = (int) (Math.random() * size);
Quote quote = quoteList.get(randomIndex);
NotificationHelper.showDefaultNotification(mContext, quote);
}
@Override
public void onDestroy() {
super.onDestroy();
L.e("hop", "service is destroyed");
}
}