Ich versuche eine App zu schreiben, die mehrere Listen verderblicher Waren aus dem internen Lager verfolgt. Ich speichere und lese serialisierte .json -Dateien, um Listen usw. zu bearbeiten und zu speichern, aber ich bin extrem festgefahren, wenn es darum geht, ein gutes Benachrichtigungsschema zu implementieren. Aus irgendeinem Grund, egal was ich tue, feuern die meisten Benachrichtigungen sofort.
private void scheduleAlarms(Context context, JSONArray inventory, String listName)
{
int DAYS_BEFORE_EXPIRY = 7; // Notify 7 days before expiration
long MILLIS_IN_A_DAY = 24 * 60 * 60 * 1000; // 1 day in milliseconds
// Set up the date formatter (force UTC if needed)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
//sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
for (int i = 0; i < inventory.length(); i++) {
try {
JSONObject item = inventory.getJSONObject(i);
String name = item.getString("name");
String expDateString = item.getString("expDate");
Date expDate = sdf.parse(expDateString); // Set to end of day (23:59:59)
long expDateMillis = expDate.getTime();
long daysNoticeMillis = item.getInt("daysNotice") * MILLIS_IN_A_DAY;
long expirationThreshold = expDateMillis - daysNoticeMillis;
Log.d("EXP DATE MILLIS:", String.valueOf(expDateMillis));
Log.d("DAYS NOTICE MILLIS:", String.valueOf(daysNoticeMillis));
long notifyTimeMillis = expDateMillis - (DAYS_BEFORE_EXPIRY * MILLIS_IN_A_DAY);
Log.d("NOTIFY TIME MILLIS:", String.valueOf(notifyTimeMillis));
long currentTimeMillis = System.currentTimeMillis();
// Only schedule alarms if we're within the notice window
if (currentTimeMillis >= expirationThreshold)
{
Intent intent = new Intent(context, NotificationReceiver.class);
String expiredOrGoing = "";
String title = "";
if (currentTimeMillis > expDateMillis)
{
expiredOrGoing = name + " has expired!";
title = "\uD83D\uDD34 Expiration notice for " + listName + " list!";
}
else if (currentTimeMillis >= expirationThreshold)
{
expiredOrGoing = name + " will expire soon!";
title = "\uD83D\uDFE0 Going notice for " + listName + " list!";
}
else if (currentTimeMillis < expirationThreshold)
{expiredOrGoing = name + " is safe for now!";}
Log.d("Debug", name + ": " + expiredOrGoing);
intent.putExtra("itemData", item.toString());
intent.putExtra("titleExtra", title);
intent.putExtra("messageExtra", expiredOrGoing);
// Use a composite unique identifier
String uniqueKey = listName + "_" + name; // Combine list and item name
int uniqueID = uniqueKey.hashCode();
// Create a new PendingIntent
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, uniqueID, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
Log.d("Debug", "Attempting to schedule notification for " + name + " at: " + notifyTimeMillis);
//Log.d("Debug", name + " - Expiration Date: " + expDateMillis);
//Log.d("Debug", name + " - daysNoticeMillis: " + daysNoticeMillis);
//Log.d("Debug", name + " - Notify time: " + notifyTimeMillis);
/*if (notifyTimeMillis < System.currentTimeMillis()) {
Log.e("AlarmError", "⛔ Not scheduling alarm for past date: " + name + ", " + notifyTimeMillis);
continue;
}*/
// Parsing the expiration date string into a Date object
Log.d("NOTIFY TIME MILLIS:", String.valueOf(notifyTimeMillis));
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Schedule the alarm
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
long bdate = new Long("1898978269000");
//alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, bdate, pendingIntent);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, notifyTimeMillis, pendingIntent);
} else
{
alarmManager.setExact(AlarmManager.RTC_WAKEUP, notifyTimeMillis, pendingIntent);
}
Log.d("Alarm", "Scheduled notification for " + name + " at " + notifyTimeMillis);
}
else {Log.d("Debug", name + " - Notify time (" + notifyTimeMillis + ") has already passed. (Optionally trigger immediately or skip.)");}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Dies ist die Berechnungslogik i will , aber wenn ich diese Zeile verwende, feuern nicht nur die Benachrichtigungen sofort, sondern auch nicht alle Benachrichtigungen, insbesondere die Benachrichtigung für "Koks":
"long expirationThreshold = expDateMillis - (DAYS_BEFORE_EXPIRY * MILLIS_IN_A_DAY);"
< /code>
Die Differenz zwischen dieser Berechnung, die ich möchte, und diesen, die ich verwende, ist das Cola -Element, der die einzige ist, die in ersteren gegenüber tatsächlich korrekt geplant wird.long notifyTimeMillis = expDateMillis - expirationThreshold;
< /code>
Ich bin jetzt seit drei Tagen festgefahren. Wenn Sie also helfen können: Vielen Dank im Voraus! Periodische Anfrage anstelle eines Onetimerequest, damit die Alarme alle 24 Stunden geplant werden, wenn der Artikel noch verläuft, aber noch nicht abgelaufen ist. Sie hätten also 14 Tage zuvor einen Alarm, dann 7, dann 3, dann 1. 2 Woche, 1 Woche, 3 Tage und 1 -Tage -Erinnerung.2025-02-27 23:13:15.392 10185-10185 WM-WorkerWrapper sma...tory.smartinventorywithsearch D Starting work for smart.inventory.smartinventorywithsearch.ExpirationCheckWorker
2025-02-27 23:13:15.393 10185-10340 Worker sma...tory.smartinventorywithsearch D Directories found: [/data/user/0/smart.inventory.smartinventorywithsearch/files/Smart Inventory/All Lists/misc, /data/user/0/smart.inventory.smartinventorywithsearch/files/Smart Inventory/All Lists/games]
2025-02-27 23:13:15.394 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1741237200000
2025-02-27 23:13:15.394 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 8640000000
2025-02-27 23:13:15.394 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740632400000
2025-02-27 23:13:15.394 10185-10340 Debug sma...tory.smartinventorywithsearch D Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC): Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) will expire soon!
2025-02-27 23:13:15.395 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) at: 1740632400000
2025-02-27 23:13:15.395 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740632400000
2025-02-27 23:13:15.395 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) at 1740632400000
2025-02-27 23:13:15.395 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1740546000000
2025-02-27 23:13:15.395 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 6912000000
2025-02-27 23:13:15.395 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1739941200000
2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Irish Penny Whistle - Key Of D | Book | Condition Good: Irish Penny Whistle - Key Of D | Book | Condition Good has expired!
2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Irish Penny Whistle - Key Of D | Book | Condition Good at: 1739941200000
2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1739941200000
2025-02-27 23:13:15.396 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Irish Penny Whistle - Key Of D | Book | Condition Good at 1739941200000
2025-02-27 23:13:15.396 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1747713600000
2025-02-27 23:13:15.396 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 7776000000
2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1747108800000
2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D coke: coke will expire soon!
2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for coke at: 1747108800000
2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1747108800000
2025-02-27 23:13:15.397 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for coke at 1747108800000
2025-02-27 23:13:15.397 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1741064400000
2025-02-27 23:13:15.397 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 21600000000
2025-02-27 23:13:15.397 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740459600000
2025-02-27 23:13:15.397 10185-10340 Debug sma...tory.smartinventorywithsearch D Ratchet & Clank 2 for PlayStation 2: Ratchet & Clank 2 for PlayStation 2 will expire soon!
2025-02-27 23:13:15.397 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Ratchet & Clank 2 for PlayStation 2 at: 1740459600000
2025-02-27 23:13:15.397 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740459600000
2025-02-27 23:13:15.398 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Ratchet & Clank 2 for PlayStation 2 at 1740459600000
2025-02-27 23:13:15.408 10185-10185 WM-SystemJobService sma...tory.smartinventorywithsearch D onStartJob for WorkGenerationalId(workSpecId=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, generation=0)
2025-02-27 23:13:15.412 10185-10226 WM-Processor sma...tory.smartinventorywithsearch D Work WorkGenerationalId(workSpecId=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, generation=0) is already enqueued for processing
2025-02-27 23:13:15.413 10185-10225 WM-WorkerWrapper sma...tory.smartinventorywithsearch I Worker result SUCCESS for Work [ id=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, tags={ smart.inventory.smartinventorywithsearch.ExpirationCheckWorker } ]
2025-02-27 23:13:15.413 10185-10185 WM-Processor sma...tory.smartinventorywithsearch D Processor 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1 executed; reschedule = false
2025-02-27 23:13:15.413 10185-10185 WM-SystemJobService sma...tory.smartinventorywithsearch D 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1 executed on JobScheduler
2025-02-27 23:13:15.415 10185-10225 WM-GreedyScheduler sma...tory.smartinventorywithsearch D Cancelling work ID 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1
2025-02-27 23:13:15.420 10185-10225 WM-PackageManagerHelper sma...tory.smartinventorywithsearch D androidx.work.impl.background.systemalarm.RescheduleReceiver disabled
2025-02-27 23:13:15.903 10185-10185 VRI[EditActivity] sma...tory.smartinventorywithsearch D visibilityChanged oldVisibility=true newVisibility=false
2025-02-27 23:13:15.915 10185-10215 HWUI sma...tory.smartinventorywithsearch D endAllActiveAnimators on 0xb4000071a6fe0980 (RippleDrawable) with handle 0xb4000071d6ea0980
2025-02-27 23:13:20.423 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received!
2025-02-27 23:13:20.440 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received!
2025-02-27 23:13:20.450 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received!
From the logs, you see "daysNoticeMillis" is definitely correct as I have them set to 100 for Elder Scrolls (8640000000 millis), 80 for Irish Penny whistle (6912000000 millis), 90 for "coke" (7776000000 millis), and 250 for Ratchet and Clank 2 (21600000000 millis). Konverter) < /p>
Das Problem ist also auf "benachrichtigen Timemillis" eingeschränkt. Aus irgendeinem Grund kehrt es vergangene Werte zurück:
27. Februar 2025 (Elder Scrolls), 19. Februar 2025 (Irish Whistle), 13. Mai 2025 (zufällig ein ordentlicher Wert für Koks? Daher, dass die Benachrichtigung vielleicht genau das Richtige für die Auslösche ist. Und dann wieder ein poopy -vergangener Wert für Ratchet und Clank 2! (25. Februar 2025).
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
String channelId = "expiration_channel"; // Must match the ID in NotificationCompat.Builder
String channelName = "Expiration Notifications";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
}
public void scheduleExpirationWorker() {
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(ExpirationCheckWorker.class)
.build();
WorkManager.getInstance(this).enqueueUniqueWork(
"ExpirationCheckWorker",
ExistingWorkPolicy.REPLACE,
workRequest
);
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
Context context = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
createNotificationChannel();
scheduleExpirationWorker();
...
}
...
// ----- Then I call that scheduleExpirationWorker() method whenever I save the lists
// ----- (which can be done with a button to save a new list, or by clicking a listview item to overwrite a list):
saveButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
String fileNameInput = saveEditText.getText().toString().trim();
File listDirectory = new File(subDirectory, fileNameInput);
if (!fileNameInput.isEmpty())
{
if (!itemsList.isEmpty())
{
// ----------------- CREATE NEW LIST FOLDER ----------------- //
if (!listDirectory.exists())
{
listDirectory.mkdirs(); // Make the directory first since it doesn't exist yet
saveInventory(listDirectory);
makeToast("'" + listDirectory.getName() + "' saved!");
}
else
{
// -------- YES or NO warning dialog for overwriting lists -------- //
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
//Yes button clicked
// ----------------- SAVE INVENTORY TO SELECTED DIRECTORY ----------------- //
saveInventory(listDirectory); // Save the data to existing directory
makeToast("'" + listDirectory.getName() + "' overwritten!");
//makeToast(listDirectory.getAbsolutePath());
saveDialog.dismiss(); // Close save list" dialog after selecting a list to load
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("This list already exists! Do you want to overwrite '" + fileNameInput + "'?").setPositiveButton("Yes", dialogClickListener)
.setNegativeButton("No", dialogClickListener).show();
}
sdFilesArray = subDirectory.listFiles(); // Refresh File array of Sub Directory Folders
importFolders.clear(); // Clear the list for the loop...
// ---------- LOOP FOR POPULATING IMPORT LIST ---------- //
for (File f : sdFilesArray)
{
String filename = f.getName();
importFolders.add(filename); // Add the folder name to the ArrayList
}
saveEditText.setText(""); // Reset the edit text to blank.
saveDialog.dismiss();
// Schedule notifications for expiring goods at the end of saving a list!
scheduleExpirationWorker();
}
else
{
makeToast("You can't save an empty list!");
}
}
else
{
makeToast("You must give the list a name!");
}
}
});
...
saveListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView parent, View view, int position, long id)
{
// ----- 2.9.4 FIX ----- //
// Get folder name by looping through sdFilesArray
// and checking for a match to the clicked item:
String folderName = sdFilesArray[position].toString();
for (File f : sdFilesArray)
{
String listDir = folderName.substring(folderName.lastIndexOf("/") + 1);
if (folderName.equals(f.toString()))
{
// -------- YES or NO warning dialog for overwriting lists -------- //
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
//Yes button clicked
if (!itemsList.isEmpty())
{
// ----------------- SAVE INVENTORY TO SELECTED DIRECTORY ----------------- //
File saveExistingList = new File(subDirectory, listDir);
saveInventory(saveExistingList);
makeToast("'" + listDir + "' overwritten!");
saveDialog.dismiss(); // Close save list" dialog after selecting a list to load
}
else
{
makeToast("You can't save an empty list!");
}
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Are you sure you want to overwrite '" + listDir + "'?").setPositiveButton("Yes", dialogClickListener)
.setNegativeButton("No", dialogClickListener).show();
}
}
// Schedule notifications for expiring goods at the end of saving a list!
scheduleExpirationWorker();
}
});
< /code>
Und hier ist die Benachrichtigungsempfängerklasse: < /p>
public class NotificationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Notification", "Notification received!");
String itemDataString = intent.getStringExtra("itemData");
if (itemDataString == null) {
Log.e("NotificationReceiver", "No valid item data received!");
return;
}
try {
JSONObject item = new JSONObject(itemDataString);
String name = item.getString("name");
String title = intent.getStringExtra("titleExtra");
String message = intent.getStringExtra("messageExtra");
// Build and send the notification
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "EXPIRATION_CHANNEL"; // Ensure this matches your NotificationChannel ID
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.use_now_status) // Replace with your actual icon
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
if (notificationManager != null) {
notificationManager.notify((int) System.currentTimeMillis(), builder.build());
}
} catch (JSONException e) {
Log.e("NotificationReceiver", "Error parsing item data: " + e.getMessage());
}
}
}
Ich versuche eine App zu schreiben, die mehrere Listen verderblicher Waren aus dem internen Lager verfolgt. Ich speichere und lese serialisierte .json -Dateien, um Listen usw. zu bearbeiten und zu speichern, aber ich bin extrem festgefahren, wenn es darum geht, ein gutes Benachrichtigungsschema zu implementieren. Aus irgendeinem Grund, egal was ich tue, feuern die meisten Benachrichtigungen sofort.[code]private void scheduleAlarms(Context context, JSONArray inventory, String listName) {
int DAYS_BEFORE_EXPIRY = 7; // Notify 7 days before expiration long MILLIS_IN_A_DAY = 24 * 60 * 60 * 1000; // 1 day in milliseconds
// Set up the date formatter (force UTC if needed) SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); //sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
for (int i = 0; i < inventory.length(); i++) { try { JSONObject item = inventory.getJSONObject(i); String name = item.getString("name"); String expDateString = item.getString("expDate");
Date expDate = sdf.parse(expDateString); // Set to end of day (23:59:59)
long expDateMillis = expDate.getTime();
long daysNoticeMillis = item.getInt("daysNotice") * MILLIS_IN_A_DAY; long expirationThreshold = expDateMillis - daysNoticeMillis;
Log.d("EXP DATE MILLIS:", String.valueOf(expDateMillis)); Log.d("DAYS NOTICE MILLIS:", String.valueOf(daysNoticeMillis));
long notifyTimeMillis = expDateMillis - (DAYS_BEFORE_EXPIRY * MILLIS_IN_A_DAY); Log.d("NOTIFY TIME MILLIS:", String.valueOf(notifyTimeMillis));
long currentTimeMillis = System.currentTimeMillis();
// Only schedule alarms if we're within the notice window if (currentTimeMillis >= expirationThreshold) { Intent intent = new Intent(context, NotificationReceiver.class);
String expiredOrGoing = ""; String title = "";
if (currentTimeMillis > expDateMillis) { expiredOrGoing = name + " has expired!"; title = "\uD83D\uDD34 Expiration notice for " + listName + " list!"; }
else if (currentTimeMillis >= expirationThreshold) { expiredOrGoing = name + " will expire soon!"; title = "\uD83D\uDFE0 Going notice for " + listName + " list!"; } else if (currentTimeMillis < expirationThreshold) {expiredOrGoing = name + " is safe for now!";}
Log.d("Alarm", "Scheduled notification for " + name + " at " + notifyTimeMillis); } else {Log.d("Debug", name + " - Notify time (" + notifyTimeMillis + ") has already passed. (Optionally trigger immediately or skip.)");} } catch (Exception e) { e.printStackTrace(); } } }
[/code] Dies ist die Berechnungslogik i will , aber wenn ich diese Zeile verwende, feuern nicht nur die Benachrichtigungen sofort, sondern auch nicht alle Benachrichtigungen, insbesondere die Benachrichtigung für "Koks": [code]"long expirationThreshold = expDateMillis - (DAYS_BEFORE_EXPIRY * MILLIS_IN_A_DAY);" < /code> Die Differenz zwischen dieser Berechnung, die ich möchte, und diesen, die ich verwende, ist das Cola -Element, der die einzige ist, die in ersteren gegenüber tatsächlich korrekt geplant wird.long notifyTimeMillis = expDateMillis - expirationThreshold; < /code> Ich bin jetzt seit drei Tagen festgefahren. Wenn Sie also helfen können: Vielen Dank im Voraus! Periodische Anfrage anstelle eines Onetimerequest, damit die Alarme alle 24 Stunden geplant werden, wenn der Artikel noch verläuft, aber noch nicht abgelaufen ist. Sie hätten also 14 Tage zuvor einen Alarm, dann 7, dann 3, dann 1. 2 Woche, 1 Woche, 3 Tage und 1 -Tage -Erinnerung.2025-02-27 23:13:15.392 10185-10185 WM-WorkerWrapper sma...tory.smartinventorywithsearch D Starting work for smart.inventory.smartinventorywithsearch.ExpirationCheckWorker 2025-02-27 23:13:15.393 10185-10340 Worker sma...tory.smartinventorywithsearch D Directories found: [/data/user/0/smart.inventory.smartinventorywithsearch/files/Smart Inventory/All Lists/misc, /data/user/0/smart.inventory.smartinventorywithsearch/files/Smart Inventory/All Lists/games] 2025-02-27 23:13:15.394 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1741237200000 2025-02-27 23:13:15.394 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 8640000000 2025-02-27 23:13:15.394 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740632400000 2025-02-27 23:13:15.394 10185-10340 Debug sma...tory.smartinventorywithsearch D Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC): Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) will expire soon! 2025-02-27 23:13:15.395 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) at: 1740632400000 2025-02-27 23:13:15.395 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740632400000 2025-02-27 23:13:15.395 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Elder Scrolls V: Skyrim (Xbox 360 / PS3 / PC) at 1740632400000 2025-02-27 23:13:15.395 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1740546000000 2025-02-27 23:13:15.395 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 6912000000 2025-02-27 23:13:15.395 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1739941200000 2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Irish Penny Whistle - Key Of D | Book | Condition Good: Irish Penny Whistle - Key Of D | Book | Condition Good has expired! 2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Irish Penny Whistle - Key Of D | Book | Condition Good at: 1739941200000 2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1739941200000 2025-02-27 23:13:15.396 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Irish Penny Whistle - Key Of D | Book | Condition Good at 1739941200000 2025-02-27 23:13:15.396 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1747713600000 2025-02-27 23:13:15.396 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 7776000000 2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1747108800000 2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D coke: coke will expire soon! 2025-02-27 23:13:15.396 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for coke at: 1747108800000 2025-02-27 23:13:15.396 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1747108800000 2025-02-27 23:13:15.397 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for coke at 1747108800000 2025-02-27 23:13:15.397 10185-10340 EXP DATE MILLIS: sma...tory.smartinventorywithsearch D 1741064400000 2025-02-27 23:13:15.397 10185-10340 DAYS NOTICE MILLIS: sma...tory.smartinventorywithsearch D 21600000000 2025-02-27 23:13:15.397 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740459600000 2025-02-27 23:13:15.397 10185-10340 Debug sma...tory.smartinventorywithsearch D Ratchet & Clank 2 for PlayStation 2: Ratchet & Clank 2 for PlayStation 2 will expire soon! 2025-02-27 23:13:15.397 10185-10340 Debug sma...tory.smartinventorywithsearch D Attempting to schedule notification for Ratchet & Clank 2 for PlayStation 2 at: 1740459600000 2025-02-27 23:13:15.397 10185-10340 NOTIFY TIME MILLIS: sma...tory.smartinventorywithsearch D 1740459600000 2025-02-27 23:13:15.398 10185-10340 Alarm sma...tory.smartinventorywithsearch D Scheduled notification for Ratchet & Clank 2 for PlayStation 2 at 1740459600000 2025-02-27 23:13:15.408 10185-10185 WM-SystemJobService sma...tory.smartinventorywithsearch D onStartJob for WorkGenerationalId(workSpecId=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, generation=0) 2025-02-27 23:13:15.412 10185-10226 WM-Processor sma...tory.smartinventorywithsearch D Work WorkGenerationalId(workSpecId=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, generation=0) is already enqueued for processing 2025-02-27 23:13:15.413 10185-10225 WM-WorkerWrapper sma...tory.smartinventorywithsearch I Worker result SUCCESS for Work [ id=1b7fecec-6d33-4f51-b7d3-60c416f9d8a1, tags={ smart.inventory.smartinventorywithsearch.ExpirationCheckWorker } ] 2025-02-27 23:13:15.413 10185-10185 WM-Processor sma...tory.smartinventorywithsearch D Processor 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1 executed; reschedule = false 2025-02-27 23:13:15.413 10185-10185 WM-SystemJobService sma...tory.smartinventorywithsearch D 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1 executed on JobScheduler 2025-02-27 23:13:15.415 10185-10225 WM-GreedyScheduler sma...tory.smartinventorywithsearch D Cancelling work ID 1b7fecec-6d33-4f51-b7d3-60c416f9d8a1 2025-02-27 23:13:15.420 10185-10225 WM-PackageManagerHelper sma...tory.smartinventorywithsearch D androidx.work.impl.background.systemalarm.RescheduleReceiver disabled 2025-02-27 23:13:15.903 10185-10185 VRI[EditActivity] sma...tory.smartinventorywithsearch D visibilityChanged oldVisibility=true newVisibility=false 2025-02-27 23:13:15.915 10185-10215 HWUI sma...tory.smartinventorywithsearch D endAllActiveAnimators on 0xb4000071a6fe0980 (RippleDrawable) with handle 0xb4000071d6ea0980 2025-02-27 23:13:20.423 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received! 2025-02-27 23:13:20.440 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received! 2025-02-27 23:13:20.450 10185-10185 Notification sma...tory.smartinventorywithsearch D Notification received! [/code] From the logs, you see "daysNoticeMillis" is definitely correct as I have them set to 100 for Elder Scrolls (8640000000 millis), 80 for Irish Penny whistle (6912000000 millis), 90 for "coke" (7776000000 millis), and 250 for Ratchet and Clank 2 (21600000000 millis). Konverter) < /p> Das [url=viewtopic.php?t=15738]Problem[/url] ist also auf "benachrichtigen Timemillis" eingeschränkt. Aus irgendeinem Grund kehrt es vergangene Werte zurück: 27. Februar 2025 (Elder Scrolls), 19. Februar 2025 (Irish Whistle), 13. Mai 2025 (zufällig ein ordentlicher Wert für Koks? Daher, dass die Benachrichtigung vielleicht genau das Richtige für die Auslösche ist. Und dann wieder ein poopy -vergangener Wert für Ratchet und Clank 2! (25. Februar 2025).[code]private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelId = "expiration_channel"; // Must match the ID in NotificationCompat.Builder String channelName = "Expiration Notifications"; NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
// ----- Then I call that scheduleExpirationWorker() method whenever I save the lists // ----- (which can be done with a button to save a new list, or by clicking a listview item to overwrite a list):
saveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String fileNameInput = saveEditText.getText().toString().trim(); File listDirectory = new File(subDirectory, fileNameInput);
if (!fileNameInput.isEmpty()) { if (!itemsList.isEmpty()) { // ----------------- CREATE NEW LIST FOLDER ----------------- //
if (!listDirectory.exists()) { listDirectory.mkdirs(); // Make the directory first since it doesn't exist yet
saveInventory(listDirectory); makeToast("'" + listDirectory.getName() + "' saved!"); } else { // -------- YES or NO warning dialog for overwriting lists -------- //
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which){ case DialogInterface.BUTTON_POSITIVE: //Yes button clicked
// ----------------- SAVE INVENTORY TO SELECTED DIRECTORY ----------------- // saveInventory(listDirectory); // Save the data to existing directory
saveDialog.dismiss(); // Close save list" dialog after selecting a list to load
break;
case DialogInterface.BUTTON_NEGATIVE: //No button clicked break; } } };
AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage("This list already exists! Do you want to overwrite '" + fileNameInput + "'?").setPositiveButton("Yes", dialogClickListener) .setNegativeButton("No", dialogClickListener).show(); }
sdFilesArray = subDirectory.listFiles(); // Refresh File array of Sub Directory Folders
importFolders.clear(); // Clear the list for the loop...
// ---------- LOOP FOR POPULATING IMPORT LIST ---------- // for (File f : sdFilesArray) { String filename = f.getName(); importFolders.add(filename); // Add the folder name to the ArrayList }
saveEditText.setText(""); // Reset the edit text to blank.
saveDialog.dismiss();
// Schedule notifications for expiring goods at the end of saving a list! scheduleExpirationWorker(); } else { makeToast("You can't save an empty list!"); } } else { makeToast("You must give the list a name!"); } } }); ... saveListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // ----- 2.9.4 FIX ----- // // Get folder name by looping through sdFilesArray // and checking for a match to the clicked item:
for (File f : sdFilesArray) { String listDir = folderName.substring(folderName.lastIndexOf("/") + 1); if (folderName.equals(f.toString())) { // -------- YES or NO warning dialog for overwriting lists -------- //
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which){ case DialogInterface.BUTTON_POSITIVE: //Yes button clicked
if (!itemsList.isEmpty()) { // ----------------- SAVE INVENTORY TO SELECTED DIRECTORY ----------------- // File saveExistingList = new File(subDirectory, listDir);
saveInventory(saveExistingList);
makeToast("'" + listDir + "' overwritten!");
saveDialog.dismiss(); // Close save list" dialog after selecting a list to load } else { makeToast("You can't save an empty list!"); }
break;
case DialogInterface.BUTTON_NEGATIVE: //No button clicked break; } } };
AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage("Are you sure you want to overwrite '" + listDir + "'?").setPositiveButton("Yes", dialogClickListener) .setNegativeButton("No", dialogClickListener).show(); } }
// Schedule notifications for expiring goods at the end of saving a list! scheduleExpirationWorker(); } });
< /code> Und hier ist die Benachrichtigungsempfängerklasse: < /p> public class NotificationReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
if (itemDataString == null) { Log.e("NotificationReceiver", "No valid item data received!"); return; }
try { JSONObject item = new JSONObject(itemDataString); String name = item.getString("name");
String title = intent.getStringExtra("titleExtra"); String message = intent.getStringExtra("messageExtra");
// Build and send the notification NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); String channelId = "EXPIRATION_CHANNEL"; // Ensure this matches your NotificationChannel ID
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) .setSmallIcon(R.drawable.use_now_status) // Replace with your actual icon .setContentTitle(title) .setContentText(message) .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true);
if (notificationManager != null) { notificationManager.notify((int) System.currentTimeMillis(), builder.build()); }
Ich verwende Fido2.AspNet Version 4.0.0-beta.16, um passwortlose Anmeldungen zu implementieren. Beim Versuch, einen Benutzer zu registrieren, erhalte ich eine Ausnahme mit der Meldung:...
Ich schreibe CUDA alles auf dem Gerät. Ich habe eine Klasse zum Emulieren von Strings, da die String-Klasse nicht auf einer GPU verwendet werden kann. Meine Klasse hat wchar_t * string in data_ und...
Ich versuche, mit meiner mit Laravel erstellten REST-API zu kommunizieren. Der Anruf mit POSTMAN wird jedoch aufgrund einer Token-Nichtübereinstimmung abgelehnt. Ich denke, ich muss das CSRF-Token in...
Ich versuche, mithilfe dieses Tutorials für UART eine Binärdatei mit avr-g++ zu kompilieren, erhalte jedoch beim Kompilieren die folgende Fehlermeldung:
main.cpp:50:20: error: designator order for...
Wenn ich den Text hervorhebe, werden bestimmte Zeilen nicht hervorgehoben, und es scheint, als ob der angezeigte Text NICHT mit dem übereinstimmt, was tatsächlich vorhanden ist.