Cannot start Widget Update With Alarm Manager and PendingIntent - android

I am trying for couple of days to solve this problem , hope someone can help me.
I am using Alarm Manager to make my widget update nay time i want (if to sue XML its only once in 30 min) so i made a pending intent and wrote it like in the examples that i found but , its updates only once when i compile the program.
Here is mu code:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
android.util.Log.w("FullTankWidget.UpdateService", "onUpdate()");
Intent updateIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, updateIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// alarmManager.setRepeating(AlarmManager.RTC, nextMinute.getTimeInMillis(),60000,pendingIntent);
long firstTime = SystemClock.elapsedRealtime();
alarmManager.set(AlarmManager.RTC, firstTime + (60 * 1000), pendingIntent);
android.util.Log.w("FullTankWidget.UpdateService", String.valueOf(firstTime));
// To prevent any ANR timeouts, we perform the update in a service
context.startService(new Intent(context,WidgetUpdateService.class));
the intent filter is writen in the manifest - defoult widget reciever
<receiver android:name=".FullTankWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/fulltank_widget_config" />
</receiver>

But your alarmManager.setRepeating() line is commented out...

First of all you should also specify your class in the Intent.
updateIntent.setClass(context, YourProviderClassName.class);
Then it is subject of the PendingIntent. There is a PendingIntent filter working on the background that does not allow two similar Intents to be set as pending. So when it is called, it will be ignored if there is a similar intent to it.
If in your appwidget provider info you have a value set for updatePeriodMillis other than zero, then the system has already set a PendingIntent for updating. This is why your new PendingIntent won't work.
The solution is to disable updatePeriodMillis and use AlarmManager instead. The AlarmManager class has methods that help you set PendingIntents the way you want. But remember you will still have only one PendingIntent at a time.

Related

Broadcast not getting called with AlarmManager

I'm having trouble with the broadcast message the alarm manager should send.
This is my code:
case Intent.ACTION_BOOT_COMPLETED:
long repeatInterval = 10*1000;
long triggerTime = SystemClock.elapsedRealtime() + repeatInterval;
AlarmManager manager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
if(manager != null){
Intent in = new Intent(context, AppReceiver.class);
in.setAction("haz");
PendingIntent inte = PendingIntent.getBroadcast(context, 500, in, PendingIntent.FLAG_UPDATE_CURRENT);
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, repeatInterval, inte);
}
break;
That's being triggered correctly with the action boot completed broadcast message, but that piece of code if I'm right should call the app receiver with the "haz" action, but that's not being called, ever.
I've tried to create a service but that's also not being called.
Anyone has any clue for what I have to do?
<receiver android:name=".YourReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- check properly boot intent syntax for manifest file -->
</intent-filter>
</receiver>
I've found a solution thanks to CommonsWare reply to my question. The answer was to have another receiver separately probably because android can't handle fast repetitions. Mine wasn't going to be that short in the end, it was for testing purposes only, but having two receivers and to call the second one with the repetitions was the answer. Thank you both #CommonsWare and #Arwy Shelke for your time and responses!!

AlarmManager triggers only the first time even when set to repeating

I am trying to figure this out for a while now.
In my activity I have set an alarm manager to trigger every 2 mins(for testing) and invoke a service via a receiver. The service is suppose to make network calls etc.
My problem is the AlarmManager triggers the first time correctly but never triggers it again. What did I miss?
In my activity I do this -
//Register an alarm manager
//If no alarm is set
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
if(!defaultSharedPref.getBoolean("isAlarmSet",false)){
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
R.string.interval,
pendingIntent);
editor = defaultSharedPref.edit();
editor.putBoolean("isAlarmSet",true);
editor.commit();
}
In my manifest:-
<receiver android:process=":remote" android:name=".receiver.AlarmReceiver" />
<service android:name=".service.AlarmService"/>
My receiver :-
public class AlarmReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AlarmService.class);
startWakefulService(context,i);
}
}
I even tried the "setRepeating" but no luck. It still triggers only once.
Can someone point out where I missed something?
Thanks in advance.
As the interval for your repeating timer you are giving a resource id - R.string.interval. This doesn't make sense, but will compile since it's an integer. If you want your interval as a resource, you'd be better of using an integer resource, but the most crucial change you need is to pass the actual value of the resource rather than the resource id. So for this, use Resources.getInteger or getString.
This should work, however I encourage you not to use a string resource at all:
manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
Integer.parseInt(getResources().getString(R.string.interval)),
pendingIntent);`
The reason you aren't seeing any triggered alarms in practice is that resource ids are very large integers, typically in the 0x8000000 range, so you're effectively setting a recurrent alarm with a very very long interval. If you wait for a month or so, the alarm would be triggered. :-)
If you want a more flexible way to schedule jobs, I would recommend this library that abstracts for you the used scheduler: https://github.com/evernote/android-job

How to schedule multiple notifications from an activity?

Can someone please tell me what changes i'd have to make to the code below to schedule multiple notifications(at different timings).
Intent notificationIntent = new Intent(this, NotificationPublisher.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
This is the part of my Android Manifest file where i added the class that extends BroadcastReceiver:
</activity>
<receiver android:name=".NotificationPublisher"/>
</application>
At present only my last scheduled notification appears.
I'm sorry for my dumb question. I was not clear on what the parameters were for PendingIntent.getBroadcast().
All I had to do was creating unique PendingIntents by changing the 2nd parameter.

App crashes when BroadcastReceiver gets called

I have two small questions;
My app's BroadcastReceiver works fine when the app is running, I get the "Tuesday at 2" toast message perfectly and it updates the app, but when I close my app, that means the app stops running, it doesn't get called but instead it crashes "Your app stopped working", so it knows it's supposed to call it, but doesn't, right?
It seems that the BroadcastReceiver gets called everyday at around 2pm, not only on Tuesdays at 2pm, I want the app to update once a week. Is it maybe because I call my setAlarm() method on my UpcomingFragment's onCreate?
In the UpcomingFragment class (where I set the alarm for it to go off each Tuesday at 2)
private void setAlarm(){
AlarmManager alarmMgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), UpdateReceiver.class);
intent.putExtra("greeting", "Hello");
PendingIntent alarmIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
calendar.set(Calendar.HOUR_OF_DAY, 14);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
}
In the BroadcastReceiver's onReceive()
public class UpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
UpcomingFragment.getInstance().update();
//if tuesday
Toast.makeText(context, "Tuesday at 2" , Toast.LENGTH_LONG).show();
}
}
Manifest:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".UpdateReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
i can't provide you with the logcat, cause it doesn't print it when it cashes, i don't know if my android studio is at fault here or my app. Thanks!
You can't manipulate Fragments inside a BroadCastReceiver's context. Essentially broadcast receivers are run inside application context and in which you can't access UI stuff.
If you would like to start an Activity once that broadcast is fired, you would need the following code:
Intent intent = new Intent(context, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Note: Accessing to UI (including Fragments) must be done in an activity context.
Update #1
It seems that the BroadcastReceiver gets called everyday at around 2pm, not only on Tuesdays at 2pm, I want the app to update once a week. Is it maybe because I call my setAlarm() method on my UpcomingFragment's onCreate?
I think I have a better approach than yours.
Getting current time and setting its day of week to Tuesday may result in weird behaviors.
Using a boot completed broadcast receiver to set the alarm may be better.
For the former, your scheduling codes should set the alarm to the nearest coming Tuesday on 2 PM. For this, this answer may be helpful.
For the latter, first, add the following permission to your manifest file.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Then, define another broadcast receiver and declare it to the manifest file.
<receiver android:name="your.package.name.BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
In your newly created broadcast receiver add this code.
#Override
public void onReceive(Context context, Intent intent) {
// Set the alarm to coming Tuesday on 2 PM
}
This ensures your app to get updated on every Tuesday on 2 PM in all circumstances.

What can I do to be sure that a background service will not start twice?

The past few days I am working on creating a background service and I noticed that quite a few people say that AlarmManager is the best way to go.
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
intent.putExtra(ONE_TIME, Boolean.FALSE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//After after 5 seconds
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 5 ,
What I wish to know is how to make sure that if this code is ran twice the service won't start 2 times. Thank you for the help in advance!
A service can't be started twice, it will remain running if you try to start it again.
See here: http://developer.android.com/guide/components/services.html#StartingAService
Edit:
However, everytime you start the service, the onStartCommand() method is called.
This is what I have used, for starting service after 30 seconds from current time,
Intent intent = new Intent(DashboardScreen.this, ServiceClass.class);
PendingIntent pintent = PendingIntent.getService(DashboardScreen.this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent);
Try it, and let me know what happen...
EDIT:
In your manifest.xml file
<service android:enabled="true" android:name=".ServiceClass" />

Categories

Resources