简体   繁体   中英

Android: Alarm not being triggered through AlarmManager

I am writing a simple Android program that triggers an alarm 15 seconds after the application initialization (plays the default ringtone and pushes a notification) through AlarmManager . Below is my code:

MainActivity.java :

package com.example.basicalarmsetter;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends AppCompatActivity {
    private int uniqueId = 0;

    // Schedules a notification in the future given the delay
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void scheduleNotification(int matchId, long delay) {
        // Construct the PendingIntent which will trigger our alarm to go off
        Intent notificationIntent = new Intent();
        notificationIntent.setAction("com.example.basicalarmsetter.MatchNotification");

        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), matchId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) ;
        long futureInMillis = SystemClock.elapsedRealtime() + delay;

        // Set off our PendingIntent
        AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
        assert alarmManager != null;
        alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
    }

    // Sets an Alarm at a future specified date
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setAlarm(long notificationDelay) {
        try {
            System.out.println("Setting alarm at " + notificationDelay + " seconds");

            // Sets off a notification after 5 seconds
            scheduleNotification(uniqueId, notificationDelay);

            uniqueId++;

        } catch (Exception ex) {
            System.out.println("Cannot print alarm!");
            System.out.println("Exception: " + ex.toString());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setAlarm(15000);
    }
}

AndroidManifest.xml :

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name="com.example.basicalarmsetter.MatchNotification"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                ...
                <action android:name="com.example.notificationtest.MatchNotification" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

MatchNotification.kt :

package com.example.basicalarmsetter

import android.app.Notification
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.net.Uri
import androidx.core.app.NotificationCompat

class MatchNotification : BroadcastReceiver() {
    var NOTIFICATION_ID = "notification-id"
    var NOTIFICATION_CHANNEL_ID = "10001";

    private lateinit var player: MediaPlayer;
    private lateinit var context: Context;

    // Construct the notification to push to the user given the teams in the match
    private fun getNotification(
        content: String
    ): Notification? {
        val builder = NotificationCompat.Builder(
            context,
            "default"
        )

        builder.setContentTitle("NBA Alarm")
        builder.setStyle(NotificationCompat.BigTextStyle().bigText(content))
        builder.setContentText(content)
        builder.setSmallIcon(R.drawable.ic_launcher_foreground)
        builder.setAutoCancel(true)
        builder.setChannelId(NOTIFICATION_CHANNEL_ID)

        return builder.build()
    }

    override fun onReceive(context: Context, intent: Intent) {
        System.out.println("Match Notification Activated.");

        this.context = context

        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val id = intent.getIntExtra(NOTIFICATION_ID, 0)
        notificationManager.notify(id, getNotification("Trigger Notification!"))

        // Retrieve the URI of the alarm the user has set
        var ringtoneUri:Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
        player = MediaPlayer.create(context, ringtoneUri)

        player.start()
    }

}

This seems strange, consdering that I have specified my MatchNotification class as a receiver in my AndroidManifest.xml file.

Devices Tested On :

  1. Motorola Moto E6 (Android 9)
  2. Emulator for Pixel 2 (API 26)

Note: The solution should have the MainActivity code in Java

This part of your code seems wrong:

notificationIntent.setAction("com.example.basicalarmsetter.MatchNotification");

You're using the class name here. You need to use the action of the broadcast receiver, the one you put in your intent filter, aka:

notificationIntent.setAction("com.example.notificationtest.MatchNotification");

Another issue: You're creating two alarms, which is unnecessary, at here:

AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
assert alarmManager != null;
alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);

At this section, following lines are unnecessary:

alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
assert alarmManager != null;

The value RTC_WAKEUP is supposed to be used with System.currentTimeMillis() , not SystemClock.elapsedRealtime() .

The final of your MainActivity.java would look like this:

package com.example.basicalarmsetter;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;

public class MainActivity extends AppCompatActivity {
    private int uniqueId = 0;

    // Schedules a notification in the future given the delay
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void scheduleNotification(int matchId, long delay) {
        // Construct the PendingIntent which will trigger our alarm to go off
        Intent notificationIntent = new Intent();
        notificationIntent.setAction("com.example.notificationtest.MatchNotification");

        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), matchId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) ;
        long futureInMillis = SystemClock.elapsedRealtime() + delay;

        // Set off our PendingIntent
        AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
    }

    // Sets an Alarm at a future specified date
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setAlarm(long notificationDelay) {
        try {
            System.out.println("Setting alarm at " + notificationDelay + " seconds");

            // Sets off a notification after 5 seconds
            scheduleNotification(uniqueId, notificationDelay);

            uniqueId++;

        } catch (Exception ex) {
            System.out.println("Cannot print alarm!");
            System.out.println("Exception: " + ex.toString());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setAlarm(15000);
    }
}

i have a solution that worked for me. Set alert as follow:

    public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        long delayInMillis = 5000;//your delay in millisecond

        Intent myIntent = new Intent(this, AlertReceiver.class);
        //any data you want to pass to your receiver class
        myIntent.putExtra(AlertReceiver.TITLE, "Scheduled Alert");
        myIntent.putExtra(AlertReceiver.CONTENT, "You have scheduled alert. Tap here to view continue...");
        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
        alarmManager.set(AlarmManager.RTC_WAKEUP, delayInMillis, pendingIntent);
    }
}

add reveiver in your manifest

<receiver android:name=".utils.AlertReceiver" />//path to your receiver

your alert receiver class can be something like this

public class AlertReceiver extends BroadcastReceiver {
private static final String TAG = "AlertReceiver";

public static final String TITLE = "title";
public static final String CONTENT = "content";

@Override
public void onReceive(Context context, Intent receivedIntent) {

    String title = receivedIntent.getStringExtra(TITLE);
    String message = receivedIntent.getStringExtra(CONTENT);
    Log.e(TAG, "onReceive: " + title + ":" + message);

    //you can show your notification or anything you want to do once you receive your alert here...



   }

}

hope this helps. Happy codding!!

Hi it seems to be like you haven't checked that is alarm running in the background or not and there must be some old code

Try the below code just paste it and nothing to do extra with AndroidManifest file and run.

class MyActivity : AppCompatActivity() {
private var alarmManager: AlarmManager? = null
private var broadcastReceiver: BroadcastReceiver? = null
private var pendingIntent: PendingIntent? = null
private val REQUEST_CODE = 45645
private var id: String? = "myname"
private var timeInMilliSeconds: Long = 15000

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
    initAlarm()
}

private fun initAlarm() {

    //creating intent
    val intent = Intent(id)
    val alarmRunning = PendingIntent.getBroadcast(
        this,
        REQUEST_CODE,
        intent,
        PendingIntent.FLAG_NO_CREATE
    ) != null

    //setting broadcast
    broadcastReceiver = getBroadcastReceiver()
    registerReceiver(
        broadcastReceiver,
        IntentFilter(id)
    )

    //setting alarm
    val ensurePositiveTime = Math.max(timeInMilliSeconds, 0L)
    pendingIntent = PendingIntent.getBroadcast(
        this,
        REQUEST_CODE,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )

    //Check if alarm is already running
    if (!alarmRunning) {
        alarmManager?.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + ensurePositiveTime, pendingIntent)

    } else {
        updateAlarm()
        Log.e("Alarm", "Alarm already running.!")
    }
}

private fun updateAlarm() {

    //calculating alarm time and creating pending intent
    val intent = Intent(id)
    val ensurePositiveTime = Math.max(timeInMilliSeconds, 0L)
    pendingIntent = PendingIntent.getBroadcast(
        this,
        REQUEST_CODE,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )

    //removing previously running alarm
    alarmManager?.cancel(pendingIntent)
    unregisterReceiver(broadcastReceiver)

    //setting broadcast
    broadcastReceiver = getBroadcastReceiver()
    registerReceiver(
        broadcastReceiver,
        IntentFilter(id)
    )

    //Check if alarm is already running
    alarmManager?.set(
        AlarmManager.RTC_WAKEUP,
        System.currentTimeMillis() + ensurePositiveTime,
        pendingIntent
    )

    Log.e("Alarm", "Alarm updated..!")

}

/**
 * This will receive broadcast after completed seconds
 */
private fun getBroadcastReceiver(): BroadcastReceiver {
    return object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            createNotification()
        }
    }
}

/***
 * It creates notification
 */
private fun createNotification() {
    val channelId = "fcm_default_channel"
    val channelName = "notification"

    val defaultSoundUri =
        RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val notificationBuilder = NotificationCompat.Builder(this@MyActivity, channelId)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentText("I am alarm from my activity")
        .setContentTitle(getString(R.string.app_name))
        .setAutoCancel(true)
        .setSound(defaultSoundUri)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setPriority(NotificationCompat.PRIORITY_HIGH)

    val mNotificationManager =
        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel =
            NotificationChannel(
                channelId,
                channelName,
                NotificationManager.IMPORTANCE_HIGH
            )
        notificationBuilder.setChannelId(channelId)
        mNotificationManager.createNotificationChannel(channel)
    }

    val notification = notificationBuilder.build()
    mNotificationManager.notify(0, notification)
}

/**
 * Use this to cancel alarm
 */
private fun cancelAlarm() {


    if (pendingIntent != null) {
        alarmManager?.cancel(pendingIntent)
    }
    if (broadcastReceiver != null) {
        unregisterReceiver(broadcastReceiver)
        broadcastReceiver = null
    }

    Log.e("Alarm", "Alarm has been canceled..!")
}

}

Below is java code

public class AlarmActivity extends AppCompatActivity {
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
private int REQUEST_CODE = 45645;
private String id = "myname";
private long timeInMilliSeconds = 5000;
static String APP_TAG = "classname";
private BroadcastReceiver broadcastReceiver;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    initAlarm();
}

private void initAlarm() {

    //creating intent
    Intent intent = new Intent(id);
    boolean alarmRunning = PendingIntent.getBroadcast(
            this,
            REQUEST_CODE,
            intent,
            PendingIntent.FLAG_NO_CREATE
    ) != null;

    //setting broadcast
    broadcastReceiver = new MyReceiver();
    registerReceiver(
            broadcastReceiver,
            new IntentFilter(id)
    );

    //setting alarm
    long ensurePositiveTime = Math.max(timeInMilliSeconds, 0L);
    pendingIntent = PendingIntent.getBroadcast(
            this,
            REQUEST_CODE,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT
    );

    //Check if alarm is already running
    if (!alarmRunning) {
        alarmManager.set(
                AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis() + ensurePositiveTime,
                pendingIntent
        );

    } else {
        updateAlarm();
        Log.e("Alarm", "Alarm already running.!");
    }
}

private void updateAlarm() {

    //calculating alarm time and creating pending intent
    Intent intent = new Intent(id);
    long ensurePositiveTime = Math.max(timeInMilliSeconds, 0L);
    pendingIntent = PendingIntent.getBroadcast(
            this,
            REQUEST_CODE,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT
    );

    //removing previously running alarm
    alarmManager.cancel(pendingIntent);
    unregisterReceiver(broadcastReceiver);

    //setting broadcast
    broadcastReceiver = new MyReceiver();
    registerReceiver(
            broadcastReceiver,
            new IntentFilter(id)
    );

    //Check if alarm is already running
    alarmManager.set(
            AlarmManager.RTC_WAKEUP,
            System.currentTimeMillis() + ensurePositiveTime,
            pendingIntent
    );

    Log.e("Alarm", "Alarm updated..!");

}

/**
 * Use this to cancel alarm
 */
private void cancelAlarm() {


    if (pendingIntent != null) {
        alarmManager.cancel(pendingIntent);
    }
    if (broadcastReceiver != null) {
        unregisterReceiver(broadcastReceiver);
        broadcastReceiver = null;
    }

    Log.e("Alarm", "Alarm has been canceled..!");
}
}

class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    WakeLocker.acquire(context);
    createNotification(context);
    WakeLocker.release();
}

/***
 * It creates notification
 * @param context
 */
private void createNotification(Context context) {
    String channelId = "fcm_default_channel";
    String channelName = "notification";

    Uri defaultSoundUri =
            RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentText("I am alarm from my activity")
            .setContentTitle(context.getString(R.string.app_name))
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .setPriority(NotificationCompat.PRIORITY_HIGH);

    NotificationManager mNotificationManager =
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel =
                new NotificationChannel(
                        channelId,
                        channelName,
                        NotificationManager.IMPORTANCE_HIGH
                );
        notificationBuilder.setChannelId(channelId);
        mNotificationManager.createNotificationChannel(channel);
    }

    Notification notification = notificationBuilder.build();
    mNotificationManager.notify(0, notification);
}

}

public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;

public static void acquire(Context c) {
    if (wakeLock != null) wakeLock.release();

    PowerManager pm = (PowerManager) c.getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
            PowerManager.ACQUIRE_CAUSES_WAKEUP |
            PowerManager.ON_AFTER_RELEASE, AlarmActivity.APP_TAG);
    wakeLock.acquire();
}

public static void release() {
    if (wakeLock != null){
        wakeLock.release();
    }
    wakeLock = null;
}
}

<?xml version="1.0" encoding="utf-8"?>

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

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.Alarmdemo">
    <activity android:name=".AlarmActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <receiver android:name="com.example.alarmdemo.MyReceiver" />
</application>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM