I want to get some arguments from Intent in onReceive() method of BroadcastReceiver class. But there's only int ALARM_COUNT = 1, although I put two args: my Parcelable Alarm object and test int (for the case when there is some problem with alarm object).
I set alarm like this:
private void setCurrentAlarm(Alarm alarm) {
long time = System.currentTimeMillis() + getClosestTimeDifference(alarm);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, time, createPendingIntent(alarm));
}
There is how I create PendingIntent variable:
private PendingIntent createPendingIntent(#NonNull Alarm alarm) {
Intent intent = new Intent(mContext, AlarmBroadcastReceiver.class);
intent.putExtra(KEY_ALARM, alarm);
intent.putExtra("TEST", 1010120012);
return PendingIntent.getBroadcast(mContext, alarm.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
And onReceive() method in my AlarmBroadcaseReceiver class:
#Override
public void onReceive(Context context, Intent intent) {
Alarm receivedAlarm = intent.getParcelableExtra(KEY_ALARM); //is always null
int receivedInt = intent.getIntExtra("TEST", -1); //the same empty, -1
}
As you can see Intent contains only some ALARM_COUNT extra, but there aren't my extras.
What to do? How can I get them?
Using flags as shown in the examples below was helpful for me.
retrun PendingIntent.getBroadcast(mContext, alarm.getId(), intent, PendingIntent.FLAG_CANCEL_CURRENT)
retrun PendingIntent.getBroadcast(mContext, alarm.getId(), intent, PendingIntent.FLAG_IMMUTABLE)
retrun PendingIntent.getBroadcast(mContext, alarm.getId(), intent, PendingIntent.FLAG_ONE_SHOT)
retrun PendingIntent.getBroadcast(mContext, alarm.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
Related
I have the below class to check if my alarms are being triggered at the exact time which I scheduled or is it differing.
I will call SetAlarm method inside the BroadCast Reciever from MainActivity. The consecutive alarms will be set by the Receiver itself by setting current time as its new string extra.
Alarms are working fine except the issue Intent string extras are not getting updated. ScheduledTime will always hold the initial value regardless of what I have set it in the setAlarm method.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Date currentTime = new Date();
String ScheduledTime = "";
if (null != intent) { //Null Checking
ScheduledTime = intent.getStringExtra("ScheduledTime");
//intent.removeExtra("ScheduledTime");
}
String message = "Current Time" + currentTime + ", Scheduled Time was: " + ScheduledTime ;
//Show Notification
long alarmMillis =(10*60*1000) ; //Set Alarm after 10 minutes
Long newTimeInMillis = System.currentTimeMillis() + alarmMillis;
currentTime.setTime(newTimeInMillis );
setAlarm(context, newTimeInMillis , currentTime.toString());
}
public void setAlarm(Context context, Long timeMillis, String ScheduledTime)
{
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmReceiver.class);
i.putExtra("ScheduledTime", ScheduledTime);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setExact(AlarmManager.RTC_WAKEUP, timeMillis, pi);
}
}
From Android official site
public static final int FLAG_UPDATE_CURRENT
Flag indicating that if the described PendingIntent already exists,
then keep it but replace its extra data with what is in this new
Intent. For use with getActivity(Context, int, Intent, int),
getBroadcast(Context, int, Intent, int), and getService(Context, int,
Intent, int).
This can be used if you are creating intents where only the extras
change, and don't care that any entities that received your previous
PendingIntent will be able to launch it with your new extras even if
they are not explicitly given to it.
So change your code from
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
to
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
I am trying to stop the alarmManager in the MainActivity from the onBackPressed() method in the Map activity. I have tried the code below but the alarmManager is not being stoped and still firing. How can I fix it?
Code in the MainActivity:
Intent intent = new Intent(MainActivity.this, GetLLRD.class);
intent.putExtra("json_data", json);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 20 * 1000, pendingIntent);
startService(intent);
Code in the Map Activity:
#Override
public void onBackPressed() {
Intent intent = new Intent(Map.this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
}
u problem is u use two different classes for intent to create and stop alarm:
Intent intent = new Intent(context,
GetLLRD.class);
Intent intent = new Intent(context,
MainActivity.class);
/** as in source code - new intent constructor */
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
if u want to check if u got the same pending intent as before you can try to use:
Intent.filterEquals(oherIntent);
to cancel alarm you have two options use flag or use the same intent on alarm:
PendingIntent.FLAG_CANCEL_CURRENT
& i advice to make pending intent as final - example:
/**
* create pending intent
*/
final PendingIntent pIntent(Intent alarmIntent) {
// Create a PendingIntent to be triggered when the alarm goes off
return PendingIntent.getBroadcast(getApplicationContext(), AlarmReceiver.REQUEST_CODE,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* cancel alarm
*/
public void cancelAlarm(Intent alarmIntent, Context context) {
try {
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
/** use flag cancel here */
PendingIntent pIntent = PendingIntent.getService(context, AlarmReceiver.REQUEST_CODE, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
/** cancel alarm */
alarm.cancel(pIntent);
} catch (Exception e) {
// handle exception here
}
}
why to make pending intent final ?
because to cancel alarm u need:
Create pending intent with the same id and appropriate intent FLAG.
(to get reference to current pending intent)
PendingIntent.getBroadcast(context, REQUEST_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Cancel that pending intent.
PendingIntent.cancel();
Cancel the alarm using alarm manager.
AlarmManager.cancel(PendingIntent);
A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.
if you are using activity, use
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
12345, intent,0);
public void onCreate() {
super.onCreate();
int idFunc = getApplicationContext().getSharedPreferences(SPREF_NAME,Context.MODE_PRIVATE).getInt("idFunc", 0);
String SecKey = getApplicationContext().getSharedPreferences(SPREF_NAME,Context.MODE_PRIVATE).getString("chave", null);
Intent intent = new Intent(getApplicationContext(), ServiceEnviaClientes.class);
Bundle bundle = new Bundle();
bundle.putString("SecKey", SecKey);
bundle.putInt("idFunc", idFunc);
intent.putExtras(bundle);
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), 10*60000, pintent);
initImageLoader(this);
}
I'm trying to pass extras provided by SharedPrefereces from an AlarmManager Intent and retrieve it within the Service, instead of access my SharedPreferences while the Service is running which I think demands more memory.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Toast.makeText(this,"task perform in service",Toast.LENGTH_SHORT).show();
Bundle bundle = intent.getExtras();
mIdFunc = bundle.getInt("idFunc");
mSecKey = bundle.getString("SecKey");
ThreadJSONBuild td=new ThreadJSONBuild();
td.start();
Log.d(TAG, "onStartCommand cycle, idFunc: "+mIdFunc+" , SecKey: "+mSecKey);
return super.onStartCommand(intent, flags, startId);
}
but I'm getting null on mSecKey and 0 on idFunc. I'm not sure if it's the best option, I'd put my SharedPreferences retrieves inside Service's onCreate() method, but not sure really.
When you call
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0,
intent, 0);
you may be getting back an existing PendingIntent that doesn't have your extras in it. You should use
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
instead. This will ensure that your extras are put in the Intent. Be aware, however, that the extras will be replaced in all users of this PendingIntent.
I am making an application that uses AlarmManager.setInexactRepeating() method, that takes a PendingIntent as a paramater.
I start this by calling my setAlarm() method
public void setRepeatingAlarm() {
Intent intent = new Intent(this, AlarmReceiver.class);
String url = getAssembledUrl();
intent.putExtra("url", url);
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
}
and stop it by stopAlarm()
private void stopRepeatingAlarm() {
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
Works just fine. However when activity gets destroyed, and user decides to stop the alarm, obviously the pending intent is null, as it gets created in the setRepeatingAlarm() method that wasnt called during current activities life.
Whats the correct way to get around this?
I could be creating the pending intent in Activity.onCreate() and that would solve this problem, however I will not be able to start the alarm again as the pending intent got canceled and needs to be recreated again (i think, unless there is a way to check the intent was canceled that i dont know about)
Actually, as it turns out
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
returns the same pending intent, if the intent is the same so, all i needed was
private void stopRepeatingAlarm() {
if(pendingIntent == null) {
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
alarmManager.cancel(pendingIntent);
}
I am adding some basic alarm functionality to my program via the use of AlarmManager and a BroadcastReceiver class (named AReceiver.java). My problem is that the data I add to the bundle attached to the Intent creating the PendingIntent appears to be lost. The only bundle data I can access in the AReceiver class is a android.intent.extra.ALARM_COUNT=1.
Here is the basic code in the main activity class creating the Intent, PendingIntent and the AlarmManager:
[Code in main activity - Notepadv3]
Intent intent = new Intent(Notepadv3.this, AReceiver.class);
intent.putExtra("teststring","hello, passed string in Extra");
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, pendingPeriodIntentId, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, timeOfNextPeriod.getTimeInMillis(), alarmIntent);
[Code in the BroadcastReceiver - AReceiver]
public void onReceive(Context con, Intent arg1) {
Bundle extrasBundle = arg1.getExtras();
Log.d("broadcast","contains teststring = " + extrasBundle.containsKey("teststring"));
Log.d("broadcast","is empty? = " + extrasBundle.isEmpty());
Log.d("broadcast","to string = " + extrasBundle.toString());
}
Debug messages say that contains teststring is FALSE, is empty is FALSE and when outputting the whole bundle, I get the android.intent.extra.ALARM_COUNT=1 value.
Any help would be greatly appreciated.
Cheers,
Tom
You have to change this line
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, pendingPeriodIntentId, intent, 0);
into this
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, pendingPeriodIntentId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
otherwise the data is lost