Alarmmanager.set() 总是在应用程序启动而不是预期时间时触发

Alarmmanager.set() always fires when application starts instead of expected time

我需要在特定时间为 运行 方法创建一个应用程序。但是,AlarmManager 从不工作,我不明白为什么。我在 11.54 将闹钟设置为 运行,但在应用程序启动时它总是 运行s,而在预期时间从不 运行s。如果您知道问题出在哪里,请发表评论。非常感谢。

这是我的清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.spr.timemanager">

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TimeManager"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".AlarmReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.ALARM"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

这是我的 MainActivity.java

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, 11);
    calendar.set(Calendar.MINUTE, 54);

    Intent intent = new Intent(this, AlarmReceiver.class);
    pendingIntent = PendingIntent.getBroadcast(this, 0 , intent, 0);
    time = (calendar.getTimeInMillis() - (calendar.getTimeInMillis() % 60000));
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

    Log.e("time", String.valueOf(time));

    time = System.currentTimeMillis();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time,pendingIntent);}
        else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP,time,pendingIntent);}
    }else {
        alarmManager.set(AlarmManager.RTC_WAKEUP,time,pendingIntent);
    }

我的报警接收器

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
        vibrator.vibrate(4000);
        Log.e("System time", String.valueOf(System.currentTimeMillis()));
    }
}

这是我的logcat

2022-05-25 11:52:27.820 16914-16914/com.spr.timemanager E/time: 1653468840000
2022-05-25 11:52:28.103 16914-16914/com.spr.timemanager E/System time: 1653468748103

P/S:如果我将这些 alarmManager.set() 代码更改为 setreapeating(),无论我如何设置,它总是在应用程序启动时和 5 秒后触发。

您正在计算您的 time(警报应该触发的时间)

time = (calendar.getTimeInMillis() - (calendar.getTimeInMillis() % 60000));

但最后在记录后你用

覆盖了这个变量
time = System.currentTimeMillis();

就在 if 级联之前。去掉这一行,看起来没必要

顺便说一句。 HOUR_OF_DAY<0 to 23> 中,所以如果你想要 11:54,那么你应该设置 10。您还可以将 Calendar.SECONDCalendar.MILLISECOND 的秒和毫秒设置为 0,而不是用 %time = calendar.getTimeInMillis()

相除

ps。你应该添加一些 alarm-in-past-setting 保护(添加一天?)

Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 10); // remember set -1 in here!!
calendar.set(Calendar.MINUTE, 54);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

// ensuring next day
while (calendar.getTimeInMillis() < System.currentTimeMillis()) {
    calendar.add(Calendar.DATE, 1);
}

time = calendar.getTimeInMillis();
Log.e("time", String.valueOf(time));

Intent intent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0 , intent, 0);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    ... set alarm for time