I have a similar use case, and in my code all triggering is done on the device only once the data snapshot has been updated. I have solved it in the following way:
- I have a listener to my database snapshot
.addSnapshotListener(new EventListener<QuerySnapshot>()
- Once the entries have been retrieved, I set up an alarm for the required dates.
- If an entry has been changed (returned in your case), the same snapshot listener is triggered again, loops through entries and cancels alarms.
Code-wise your main activity or service could have something like this:
db.collection("items").addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if(e==null) {
ArrayList<Item> itemsList = new ArrayList<>();
itemsList.addAll(documentSnapshots.toObjects(Item.class));
for(Item item:itemsList){
if(item.isReturned()){
cancelAlarm(item);
}
else {
setAlarm(item);
}
}
} else {
// error handling
}
}
});
Intent intent;
PendingIntent pendingIntent;
final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
public void setAlarm(Item item){
intent = new Intent(context, ItemBroadcastReceiver.class).putExtra("ID", item.getUuid());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, item.getUniqueIntegerCode(), intent, 0);
am.set(AlarmManager.RTC_WAKEUP, item.getDateTimeDue().minusDays(1), pendingIntent);
}
public void cancelAlarm(Item item) {
if(intent != null && pendingIntent != null){
am.cancel(pendingIntent);
/// if item needs to be saved, add your firestore set() routine
}
}
And your broadcast receiver that reacts on the trigger:
public class ItemBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startActivity(intent); // example, add necessary reaction
}
}