Winston Lycan
Winston Lycan

Reputation: 97

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

I need to create an application to run a method at a specific time. However, AlarmManager never works, and I do not understand why. I set up the alarm to run at 11.54, but it always runs when the application starts and never runs at the expected time. If you know what is the problem, please comment. Thank you very much.

This is my Manifest

<?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>

And this is my 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);
    }

My AlarmReceiver

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()));
    }
}

This is my 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: if I change these alarmManager.set() code into setreapeating(), it always fires when the application starts and 5 seconds afterward, no matter how I set it.

Upvotes: 0

Views: 45

Answers (1)

snachmsm
snachmsm

Reputation: 19273

you are calculating your time (when alarm should fire)

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

but at very last after logging you are overriding this variable with

time = System.currentTimeMillis();

just before if cascade. remove this line, looks unnecessary

btw. HOUR_OF_DAY is in <0 to 23>, so if you want 11:54 exacly then you should set 10. you can also set seconds and millis with Calendar.SECOND and Calendar.MILLISECOND to 0 instead of dividing with % and then your time = calendar.getTimeInMillis()

ps. you should add some alarm-in-past-setting protection (add a day?)

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

Upvotes: 1

Related Questions