I need to set Alarm on 9.00 AM, 11 AM and 1PM in everyday.
Simple solution is to use three different pending Intent but Is it any other way to implement same with one pending Intent?
Thanks in Advance!
Thanks, Got solution
Only need to change request code in same Intent. It will not cancel previous alarm. Click Here for solution
If you have a limited number of alarms that at any time need to be scheduled, maybe use one PendingIntent for each alarm can be fine.
However if you have a potentially unlimited (or maybe just a lot) number of alarms to be scheduled, I think that a better approch can be to provide a scheduler that can act over the scheduling information. For example, if you need to create something like a calendar where you can set one or more Event for each day, you should consider this approch.
You can take a look at the Alarm section of tha Android Calendar project
As you can see there is a class named AlarmScheduler in which you have a method
void scheduleNextAlarm(Context context, AlarmManagerInterface alarmManager,
int batchSize, long currentMillis)
That determines the next alarm that need to be scheduled.
In the specific implementation you can see that the method calls another method:
queryUpcomingEvents()
that operates over a content provider (Calendar provider) and gets the upcoming events.
Each time you trigger a new Alarm you can reschedule a new one, looking in the content provider (or wherever you store your scheduling information), or you can applay different scheduling policiy. For example if an user create a new remider for an Event on the calendar you need to reschedule the alarms (for example you could decide to schedule all the alarms for today, or just the next alarm).
In my applications I usually use the following code (inside the onReceive() of the BroadcastReceiver that is triggered when the alarm fires):
private void restartScheduler(Context context){
Intent t = new Intent("it.gvillani.socialapp.alerts.SCHEDULE_REQUEST");
context.sendBroadcast(t);
}
And then of course I have a BroadcastReceiver that waits for that action and try to reschedule the alarms:
public class SchedulerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
if (intent.getAction().equals("it.gvillani.socialapp.alerts.SCHEDULE_REQUEST")) {
startScheduler(c);
}
}
private void startScheduler(Context c) {
AlarmScheduler.clearAlarms(c);
AlarmScheduler.scheduleNextAlarm(c);
}
}
Related
Update
I gave up using ACTION_TIME_TICK because when click the physical button of a locked phone, it will also sent ACTION_TIME_TICK even the phone is still locked. That may make trouble if I keep pressing the key to wake up the phone.
Edit
The original purpose of this question:
Update widget text every 60s(not TextClock)?
Can I use ACTION_TIME_TICK to update android time widget?
I find an app called KWGT(Kustom Widget) and seems like using background?foreground service to update every minute. Its service(shows notification, so I' m sure it is service) lives longer than mine(alarm + foreground service).
How do KWGT do this? Its help site says: Kustom was using close to 0 resources when it was allowed to ignore battery optimization (because targeting old releases) and new version acts like the same.Does it mean alarm using AlarmManager.RTC mode?
I have an Android AppWidget that shows HH:mm, update every 60 seconds, it works but still has some problem. Here is what I’ ve got:
I’ ve tried TextClock, it seems good, but I still need to update some other text when time ticks, like “count down: 3 min”、“count down: 2 min”.
I use the AlarmManager, send broadcast every minute to update my widget. I ‘m a little worry about my device’ s battery. Another problem is, when I change my device’ s time, TextClock get the new time immediately, but my widget text not.
I know how TextClock do it: intent ACTION_TIME_TICK, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED sent by the system. The annotation says: “You cannot receive this through components declared in manifests, only by explicitly registering for it with Context.registerReceiver()”.
So, should I register that receiver in a service? I think it will not work very long because my process can not run forever. How those system time widgets do this? What' s the best way in 2021? My minSdk is API 26, if there is some better way after it, I can change to higher version.
My Alarm:
fun startAlarm() {
val calendar: Calendar = Calendar.getInstance()
calendar.set(Calendar.MILLISECOND, 0)
calendar.set(Calendar.SECOND, 0)
calendar.add(Calendar.MINUTE, 1)
val alarmIntent = Intent(context, MyWidget::class.java)
alarmIntent.action = MyWidget.ACTION_AUTO_UPDATE
val pendingIntent = PendingIntent.getBroadcast(
context,
ALARM_ID,
alarmIntent,
PendingIntent.FLAG_CANCEL_CURRENT
)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
// RTC does not wake the device up
alarmManager.setRepeating(
AlarmManager.RTC,
calendar.timeInMillis,
INTERVAL_MILLIS.toLong(), // Value will be forced up to 60000 as of Android 5.1
pendingIntent
)
}
fun registerReceiver says:
Note: this method cannot be called from a BroadcastReceiver component; that is, from a BroadcastReceiver that is declared in an application's manifest. It is okay, however, to call this method from another BroadcastReceiver that has itself been registered at run time with registerReceiver, since the lifetime of such a registered BroadcastReceiver is tied to the object that registered it
What does this mean? Can I regeister it in class MyWidget : AppWidgetProvider()? What is the correct context?
Here is the receiver register in TextClock:
// OK, this is gross but needed. This class is supported by the
// remote views mechanism and as a part of that the remote views
// can be inflated by a context for another user without the app
// having interact users permission - just for loading resources.
// For example, when adding widgets from a managed profile to the
// home screen. Therefore, we register the receiver as the user
// the app is running as not the one the context is for.
getContext().registerReceiverAsUser(
mIntentReceiver,
android.os.Process.myUserHandle(),
filter,
null,
getHandler()
);
And registerReceiverAsUser is a function with #UnsupportedAppUsage so I think it can not help me.
Thanks a lot.
The best approach is to use TextClock or AnalogClock if you can. These update each minute (or second for AnalogClock on Android 12) without your application's process needing to run.
ACTION_TIME_TICK is only sent to registered receivers, which means you won't receive it when your application isn't running. The only plausible way to keep your app running would be to use a foreground service, requiring showing a notification to the user.
You can override listed method in the class which extends from AppWidgetProvider like this:
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
Log.d("TAG", "mythou--------->onReceive Reason: " + intent.getAction());
}
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
context.getApplicationContext().registerReceiver(this, filter);
}
In my app i am using AlarmManagerto start service every week on a specific time. But in some cases instead of waiting another 7 days I need to call the service on the next day. Because of that I'm not using reapeating alarm but instead in the started service I'm creating new Alarm and set it to a specific date. Something like this:
public class AlarmService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//do something
//setting new alarm
AlarmManager alarmMng = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this,AlarmService.class);
PendingIntent alarmIntent = PendingIntent.getService(this, 0, i, 0);
Calendar c = Calendar.getInstance();
if(something) alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24,alarmIntent);
else alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24*7,alarmIntent);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
Everything works fine but I wonder if this is good way to do it. Is it a good idea to create new alarm from service that was just called by one? Is it considered bad programming practice? If so how else should I handle it?
Is it considered bad programming practice?
No - this is a fine use case for creating alarm events. If you look at the documentation, use of AlarmManager is intended to send events to your app even if it is not running. Receiving those events in a Service that then schedules another alarm event is perfectly fine. The rest of my answer is intended to explain how to answer the other question you ask:
Is it a good idea to create new alarm from service that was just
called by one?
To determine if you need a Service really depends on the "do something" portion of your code more than setting the alarm. For example, you might be fine using a IntentService or even a BroadcastReceiver.
EDIT:
In other words, you will need a background process to handle this. Determining the appropriate background process (Receiver or Service) depends on how much processing needs to be done. Generally, setting an alarm all by itself could probably be handled in a Receiver but if it takes too long to process (e.g. more than 10 seconds) you will get an ANR (Application Not Responding) crash. That's when you need a service.
END EDIT..
This is a good post about services: Service vs IntentService
Specifically, the concern you should have is if your service is called multiple times, you should probably include code to cancel any previous alarms created by it, before setting a new alarm.
EDIT: Also, you are not "creating a new service" or "new alarm" each time. Services will have onStartCommand called each time an intent is sent to it (by the AlarmManager or by any other means). A new instance is not created unless it is not already instantiated.
I have a broadcast receiver class, which I want to connect to a broadcast receiver in the main activity class, in order to call a method which originally called the broadcast receiver CLASS.
I have been struggling to find out how this would be done, and I think I am over complicating things. I saw something about using registerReceiver in the main activity class, but I don't think this is what I want.
This is the code setup in case I confused you.
MainActivity.class
public class MainActivity extends AppCompatActivity {
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
restartAlarm();
}
}
private void restartAlarm(){
//Do some stuff and call the RecursionReceiver class
}
}
RecursionReceiver.class
public class RecursionReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Somehow call the broadcast receiver in the main class
}
}
EDIT: I will provide some more details.
What I am trying to do is set an alarm that will trigger at a certain point, which will call the broadcast receiver class. This class should in turn call the reset alarm method, which will reset the alarm.
No, I can't use a repeating alarm for what I want. This is because I am setting another alarm that requires this alarm. The other alarm will be set to trigger at a certain time, plus or minus a random number of milliseconds. It should not trigger at the same interval. However, I need it to start after the same period of time. So if I have that alarm to trigger every day at 6pm and want a offset of + or - 60000 milliseconds (one minute), the alarm will trigger within the boundaries. I have accomplished this, but I need a way to reset the alarm at the desired time, not at the trigger time. Plus I need to redo calculations to change the offset time.
My solution to this is have a second alarm that does nothing but recall the method to start both alarms at the time when the offset alarm SHOULD reset. If there is an easier way to set the second utility alarm, then let me know. Otherwise, I am confused about how to recall the method in the activity class from a broadcast receiver class.
The solution I found said I needed to do it with registerReceiver and have a BroadcastReceiver in the activity class. Then I could activate the receiver from the one that the alarm calls, and call the method from the receiver in the same class as the method. But there was no explanation for the code and it has highly confused me.
I am confused on how to make the receiver work from inside the class. I have made external broadcastreceivers work, but not local ones.
In order to implement a reminder, I need to set a memo like: "starting from today, show a memo, each friday, one week yes and one no"
So, I think I can determin for each memo, what is the next date I have to show it. And then pass this date to a Timer like this:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
//show my memo
});
}}, date); //
Supposing now is Mon 26/11/2012 how can I determine when occurs the first friday (according to the aforementioned memo?
I'm not sure this mechanism is enough good, if someone can suggest me another approch I would be grateful.
Timer is not a good class to use for this. You should take a look at AlarmManager and schedule your events using that.
You can use AlarmManager.set() to set a specific alarm, AlarmManager.setInexactRepeating() to set a repeating alarm that has some flexibility in terms of exactness, setRepeating() to set a precise repeating alarm.
In all cases you set up a PendingIntent that gets launched when the alarm fires, and your application should be prepared to handle that intent correctly.
Remember that you don't necessarily need to take action when that PendingIntent is fired: you can just check if the conditions are right (for example, you can add some logic as to whether the user should be notified or not at that point).
More about AlarmManager and PendingIntent:
http://developer.android.com/reference/android/app/AlarmManager.html
http://developer.android.com/reference/android/app/PendingIntent.html
Also, remember that you have to add a broadcast receiver to the "boot sequence completed" event so that you can reinstall your alarms after the device has been rebooted, since alarms don't persist across reboots.
I'm currently having a problem integrating AlarmManager and BroadcastReceiver.
Im my app, I'm running a background service that runs regardless that app is running or not. I think I get this part working fine. The background service keeps an array that changes based on user's location. However, at 8:00am everyday, I want the app to reset the array variable to default. After much looking around online, it seems like the way to do this is via AlarmManager (to initiate the task every 8:00am) and using BroadcastReceiver (to receive the alarm, and perform the task).
So basically the code goes something like this:
public class BackgroundService extends Service {
private ArrayList thisArray;
private BroadcastReceiver thisReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
setArrayToDefault();
}
}
#Override
public void onCreate(){
super.onCreate();
Calendar cal = new GregorianCalendar();
cal.add(Calendar.MINUTE, 2); //example
this.registerReceiver(thisReceiver, new IntentFilter("BackgroundService"));
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), ONE_MINUTE, "what to put here?"); //example, repeat every minute
}
private void setArrayToDefault(){
//here, the array will be changed back to default values
}
}
My main issue is on how to set the AlarmManager to call thisReceiver everytime it's set. Any idea? Is my approach correct?
Im my app, I'm running a background service that runs regardless that app is running or not.
Please don't. This is why users attack us with task killers and the Force Stop from the Manage Services screen in Settings.
My main issue is on how to set the AlarmManager to call thisReceiver everytime it's set. Any idea?
You are not registering the BroadcastReceiver, so AlarmManager will not be able to contact it.
Please please please please please please please redesign your service such that it does not have to run all of the time. Android will be killing off your service due to old age, anyway, so if you want a reliable and stable app, you need to do this redesign, anyway.