I am trying to trigger an alarm once at a specific time everyday. But like all others I am using setExact() instead of setRepeating(). Alarm is firing at the correct time. But once it fires it keeps on repeating itself after every 5sec. How can I trigger it only once in a day at a specific time? Here is my code:
MainActivity.java:
public class MainActivity extends AppCompatActivity implements Observer {
private AlarmManager alarmManager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BroadcastObserver.getInstance().addObserver(this);
}
#Override
public void update(Observable o, Object arg) {
Log.e("MainActivity", "Alarm set through observer");
cancelAlarm();
setAlarm();
}
#Override
protected void onStart() {
super.onStart();
if (!checkAlarm()) {
setAlarm();
}
}
public void setAlarm() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 14);
calendar.set(Calendar.MINUTE, 13);
calendar.set(Calendar.SECOND, 0);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyReceiver.class);
intent.setAction(MyReceiver.ACTION_RECEIVER);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
private boolean checkAlarm() {
Intent intent = new Intent(this, MyReceiver.class);
intent.setAction(MyReceiver.ACTION_RECEIVER);
boolean isSet = PendingIntent.getBroadcast(this, 1001, intent, PendingIntent.FLAG_NO_CREATE) != null;
Log.e("MainActivity", isSet + " :Alarm is set");
return isSet;
}
#Override
protected void onStop() {
super.onStop();
cancelAlarm();
}
private void cancelAlarm() {
Intent intent = new Intent(this, MyReceiver.class);
intent.setAction(MyReceiver.ACTION_RECEIVER);
final PendingIntent pendingIntent =
PendingIntent.getBroadcast(MainActivity.this, 1001, intent,
PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null) {
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
}
}
BroadcastReceiver:
public class MyReceiver extends BroadcastReceiver {
public static final String ACTION_RECEIVER = "Receiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.e("MainActivity", "triggered");
BroadcastObserver.getInstance().updateValue(intent);
}
}
BroadcastObserver:
public class BroadcastObserver extends Observable {
private static BroadcastObserver instance = new BroadcastObserver();
public static BroadcastObserver getInstance(){
return instance;
}
private BroadcastObserver(){}
public void updateValue(Object data) {
synchronized (this) {
setChanged();
notifyObservers(data);
}
}
}
once it fires it keeps on repeating itself after every 5 sec
You are setting an alarm for 14:13 for a given day. When the alarm fires the Observer is notified and it sets the exact same alarm (for 14:13).
At this point we're past 14:13, so the alarm will fire immediately, notifying the Observer again, resulting in an infinite loop of the above steps.
The simplest solution might be to check the time when setting the alarm and if it's in the past, then add a day to it:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 14);
calendar.set(Calendar.MINUTE, 13);
calendar.set(Calendar.SECOND, 0);
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
To avoid memory leaks you need to remove the Observer when appropriate:
#Override
protected void onDestroy() {
BroadcastObserver.getInstance().deleteObserver(this);
super.onDestroy();
}
Also, cancelling the alarm in update() is redundant. This is not a repeating alarm, so it makes no sense to cancel it after it fired.
Related
I am working on alarm with android and broadcast receiver. Setting up and playing an alarm works but I cannot turn off the alarm. I have two button for set alarm and stop alarm .My codes is here;
public class MainActivity extends AppCompatActivity {
Button btn;
private Button startAlarmBtn;
private TimePickerDialog timePickerDialog;
final static int REQUEST_CODE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button cancel;
startAlarmBtn = (Button) findViewById(R.id.startAlarmBtn);
startAlarmBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openPickerDialog(false);
}
});
cancel=(Button)findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopAlarm();
}
});
}
private void openPickerDialog(boolean is24hour) {
Calendar calendar = Calendar.getInstance();
timePickerDialog = new TimePickerDialog(
MainActivity.this,
onTimeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
is24hour);
timePickerDialog.setTitle("Alarm Ayarla");
timePickerDialog.show();
}
TimePickerDialog.OnTimeSetListener onTimeSetListener
= new TimePickerDialog.OnTimeSetListener(){
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
Calendar calNow = Calendar.getInstance();
Calendar calSet = (Calendar) calNow.clone();
calSet.set(Calendar.HOUR_OF_DAY, hourOfDay);
calSet.set(Calendar.MINUTE, minute);
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
if(calSet.compareTo(calNow) <= 0){
calSet.add(Calendar.DATE, 1);
}
setAlarm(calSet);
}};
private void setAlarm(Calendar alarmCalender){
Toast.makeText(getApplicationContext(),"Alarm OK!",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getBaseContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(), REQUEST_CODE, intent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmCalender.getTimeInMillis(), pendingIntent);
}
private void stopAlarm(){
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE,
new Intent(getApplicationContext(), AlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
pendingIntent.cancel();
}
}
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alarmUri == null)
{
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);
ringtone.play();
}
}
How do I turn off the alarm?
My other question is, is it appropriate to have them in the main thread?
Should I use AsyncTask or multi-threading?
Thank you.
The alarm is not stopping because you don't have a handle to the ringtone instance you are playing.
I suggest you add a timer to auto stop the ringtone, or you create a global instance of the ringtone, which on second thought might be a bad idea, because if you forget to clean up, it may leak and cause other problems.
A simple approach to timing this is as shown below:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alarmUri == null)
{
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);
ringtone.play();
new CountDownTimer(30000, 1000) { // a timer for 30 seconds, that updates approximately every second
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
// stop your ringtone here, or do other necessary stuff here
// you might want to check if the ringtone was not stopped before this method
}
}.start();
}
}
In response to your second question, you could as well use a thread with a handler or runnable to manage the ringtone accordingly. An AsyncTask may be too much work for something relatively simple.
I create an alarm, it works but the problem is that also after the time I set, the alarm start in the moment I open the application and sometimes, also when is closed and I don't open app. I have this problem since a lot of days, could someone help me?
This is my code:
ScarsdaleHome.java
public class ScarsdaleHome extends Fragment implements OnClickListener{
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
public ScarsdaleHome() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.scarsdale_home_activity, container, false);
Calendar calend = Calendar.getInstance();
calend.setTimeInMillis(System.currentTimeMillis());
calend.set(Calendar.HOUR_OF_DAY, 19);
calend.set(Calendar.MINUTE, 31);
calend.set(Calendar.SECOND, 00);
Intent myIntent = new Intent(getActivity(), MyReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, myIntent,0);
alarmManager = (AlarmManager)getActivity().getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calend.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
return rootView;
}
public static ScarsdaleHome newIstance(){
ScarsdaleHome frag= new ScarsdaleHome();
return frag;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
MyReceiver.java
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent service1 = new Intent(context, MyAlarmService.class);
context.startService(service1);
}
}
You have called the setRepeating() method of the AlarmManager class, which schedules a repeating alarm that is fired irrespective of whether the user has opened the app or not. If you want to start your Service only when the user opens the app, then use
alarmManager.set();
or
alarmManager.setExact();
to do so. This will schedule the Service to start only when the user opens the app.
EDIT:
Define your alarm like this:
if(PendingIntent.getBroadcast(getActivity(), 0,
myIntent,
PendingIntent.FLAG_NO_CREATE) == null){
pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, myIntent,0);
alarmManager = (AlarmManager)getActivity().getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calend.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
This will not reset the alarm if it is already set.
I want to implement a Service which permit to show a notification (daily, or after XX minutes) even if I close the application. (Actually, when I press back button, I finish the MainActivity...)
I need a runnable notification even if I didn't start the application (after rebooting the device for example, of course when the trigger is declanched)...
I tried some clear examples and tutorials but I doesn't find what I need.
Please HELP!
Thanks in advance,
Mohamed
You can do it with alarm manger:
public class AlarmHelper {
private Context context;
private AlarmManager alarmManager;
private static final String TAG = "AlarmHelper";
public final static String ALARM_ALERT_ACTION = "com.android.alarmclock.ALARM_ALERT";
public AlarmHelper(Context context) {
this.context = context;
alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
}
public void setNotifyAlarm(Long milliSecond) {
PendingIntent pendingIntent = getNotifyPendingIntent();
alarmManager.cancel(pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, milliSecond, pendingIntent);
// alarmManager.set(AlarmManager.RTC_WAKEUP, milliSecond, sender);
}
public void cancelNotifyAlarm() {
PendingIntent pendingIntent = getNotifyPendingIntent();
alarmManager.cancel(pendingIntent);
}
private PendingIntent getNotifyPendingIntent() {
Intent intent = new Intent(context, AlarmExpireService.class);
return PendingIntent.getService(context, 0, intent, 0);
}
public void setExpireAlarm(int minute) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, minute - 1);
PendingIntent pendingIntent = getExpirePendingIntent();
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
pendingIntent);
}
public void cancelExpireAlarm() {
PendingIntent pendingIntent = getExpirePendingIntent();
alarmManager.cancel(pendingIntent);
}
private PendingIntent getExpirePendingIntent() {
return PendingIntent.getService(context, 0, new Intent(context,
AlarmExpireService.class), 0);
}
}
Now in the AlarmExpireService.java:
public class AlarmExpireService extends Service {
// private static final String TAG = "AlarmExpireService";
private static final String TAG = "AlarmExpireService";
#Override
public void onCreate() {
super.onCreate();
//your logic for start activity or generate notification.
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
AppLog.Log(TAG, "On start command");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Now Register service in the manifest file:
<service android:name="your_package.AlarmExpireService" />
For just call a method from AlarmHelper's setNotifyAlarm method and your work is done pass the time in millisecond (it will start after that time and notification will be pop up).
For more information take a reference of this links:
1. AlarmManager
2. Service
3.Pending Intent
I have created the start alarm as shown below
public class MyScheduleReceiver extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 5;
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager service = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyStartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
service.setInexactRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), REPEAT_TIME, pending);
I crate this for stop alarm and i call it from main activity.Manifest i think is ok...Work repeat but no stop!!!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.setup);
sendBroadcast(new Intent(this,MyScheduleReceiver.class));
}
public void StopRepeat(View view) {
sendBroadcast(new Intent(this,MyStopReceiver.class));
}
public class MyStartServiceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Repeat service!.",
Toast.LENGTH_LONG).show();
}
public class MyStopReceiver extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 5;
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager service = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent istop = new Intent(context, MyStartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, istop,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
service.cancel(pending);
But the service is not stopping. What might be the issue?Thanks.
The simplest option is to restart your device. (If you created a BOOT_COMPLETED listener just remove it for now.)
You can also cancel an alarm by passing the PendingIntent you used to create the alarm to AlarmManager#cancel(). You have already written the code to do this, but do you have a Button with the XML attribute android:onClick="StopRepeat" in setup.xml? Did you click it?
Solution
We eventually discovered you had a mistake in your Manifest file, so MyStopServiceReceiver was never called...
I've a service that runs after android starts. I'd like show a toast every days at 9am. The problem is: how can I implement the code (alarmamanger within service)?
Start service after boot:
public class AutoStart extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.example.startatboot.UnUsedService");
context.startService(serviceIntent);
}
}
public class Service extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Toast.makeText(UnUsedService.this, "Start Alarm", Toast.LENGTH_LONG).show();
}};
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0); AlarmManager am = (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, new Intent(context, MyClass.class), PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Just replace your code with my code,
public class Service extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Toast.makeText(UnUsedService.this, "Start Alarm", Toast.LENGTH_LONG).show();
}};
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0); AlarmManager am = (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, new Intent(context, AlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Now create a new class AlarmReceiver in the same package and add the following code to it.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();
}
}
Now define it in the PendingIntent of the Alarm.
Add following code in the manifest file,
<receiver android:name=".AlarmReceiver" />
Now run your application. that's it. It will definitely show a toast at 9.
Let me know if it worked or not.