Unable to set proper Context to cancel alarmmanage

2019-07-25 16:36发布

问题:

I have created an alarm with a notification and a button to stop the alarm but it seems that there is some issue with the Contextthat I have to get in order to cancel the AlarmManager.

I have researched a lot and I think I have applied most of the things I found but somehow can't get this to work.

I am aware the PendingIntent has to be the same and it appears to me they are with the same request codes too.

AlarmSlave.class - Sets Alarm

 public class AlarmSlave /*extends Service*/ {

    private static final String STOP_ACTION = "STOP";

    private int hourOfDay;
    private int minuteOfHour;


    private AlarmManager alarmManager;
    private PendingIntent pendingIntent;

    public AlarmSlave() {

    }
AlarmSlave(int hour, int minute) {

        hourOfDay = hour;
        minuteOfHour = minute;

    }

    public void setAlarm(Context context) {

        alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        /*Intent intent = new Intent(context, AlarmReceiver.class);*/
        pendingIntent = PendingIntent.getBroadcast(context, 327, new Intent(context, AlarmReceiver.class), 0);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
        calendar.set(Calendar.MINUTE, minuteOfHour);
        alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

        Log.d("Ctx setAlarm ", context.toString());

    }

AlarmReceiver.class - Plays Ringtone Pretty Much.

    public class AlarmReceiver extends WakefulBroadcastReceiver{

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

        /*MainActivity inst = MainActivity.instance();

        Log.d("Testing","this is here"+inst);*/

        Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        if (alarmUri == null){
            alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
        }

        Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);
        ringtone.play();


        ComponentName componentName = new ComponentName(context.getPackageName(), AlarmService.class.getName());
        startWakefulService(context, (intent.setComponent(componentName)));
        setResultCode(Activity.RESULT_OK);
    }
}

AlarmService.class - This is what shows the notification, the content intents are working fine but for the action they are not.

    public class AlarmService extends IntentService {

    public static final String STOP_ACTION = "STOP";

    public AlarmService() {
        super("AlarmService");
    }


    @Override
    public void onHandleIntent(Intent intent) {
        sendNotification("Wake Up! Wake Up");
    }

    private void sendNotification(String msg) {
        Log.d("AlarmService", "Preparing to send notification...:" + msg);
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);

        //PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 327, new Intent(getApplicationContext(), AlarmActivity.class), 0);
        int notificationId = 1; // just use a counter in some util class...
        PendingIntent dismissIntent = AlarmActivity.getDismissIntent(notificationId, getApplicationContext());

        /*Intent stopIntent = new Intent(this, AlarmSlave.class);
        stopIntent.setAction(STOP_ACTION);

        PendingIntent stopPendingIntent = PendingIntent.getBroadcast(this, 10, stopIntent, 0);*/

        NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(getApplicationContext())
                .setContentTitle("Alarm")
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg)
                .addAction(R.mipmap.ic_launcher_round, "STOP", dismissIntent);

        alarmNotificationBuilder.setContentIntent(dismissIntent);
        notificationManager.notify(1, alarmNotificationBuilder.build());

        Log.d("AlarmService", "Notification Sent");
    }
}

ContextApp.class - This is what generates Context for me.

public class ContextBitchApp extends Application {

 private static Context mContext;

@Override
public void onCreate(){
    super.onCreate();
    mContext = getApplicationContext();
}

public static Context getContext(){
    return mContext;


   }
}

Pardon for some of the language in the naming, done out of utter frustration after trying several different things over the period of two days.

EDIT: This is what my Log is showing for Context

05-13 09:37:55.208 24235-24235/<omitted> D/Ctx setAlarm: <omitted>.ContextBitchApp@7709bb7
05-13 09:41:18.760 3244-3244/<omitted>:remote D/Ctx onReceive: android.app.ReceiverRestrictedContext@2c317d9
05-13 09:41:18.760 3244-3244/<omitted>:remote D/Ctx cancelAlarm: android.app.ReceiverRestrictedContext@2c317d9

EDIT: Updated Code

回答1:

I am using 0 instead PendingIntent.FLAG_UPDATE_CURRENT and cancel method work fine, Try to use 0 in both intents or try to set PendingIntent.FLAG_CANCEL_CURRENT to the pending intent in your private void cancelAlarm(Context context) method.



回答2:

All your mucking around with Context is causing your problem. You absolutely positively cannot do this:

private static  Context ctx = ContextBitchApp.getContext();
private static final Context ctxCopy = ctx;

a static variable gets initialized when the class is loaded. At this time, you have no idea what ContextBitchApp.getContext() will return.

In any case, you don't need to try to save Context and all that. Just always use getApplicationContext() when you need a Context to pass as a parameter to PendingIntent.getBroadcast().

Also, after calling AlarmManager.cancel(), you can also cancel the PendingIntent by calling cancel() on it.