Android Alert Dialog causing crash on .show() - android

So my app has a timer that displays in the main activity as it is counting down. I want an alarm to play when the timer is done, so I schedule an intent that sounds the alarm using AlarmManager and a class to extend BroadcastReceiver.
Everything works fine until the alarm goes off. I traced the crash to the line where I call show() on my AlertDialog. I feel like it has something to do with the application context and the code not being in MainActivity or something, but I can't seem to find anything with a similar configuration and the same crash source.
Here is the alert dialog code
public class SoundAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
...///Play sound code is here and works
final CharSequence [] options = {"OK"};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Title");
builder.setMessage("Beer is done!");
builder.setCancelable(false);
builder.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if(which == 0) {
mp.stop();
mp.release();
}
}
});
AlertDialog alert = builder.create();
alert.show();
... //other stuff
Here is the code that schedules with the AlarmManager which is found in MainActivity.java:
//Schedule the alarm
Intent alarmIntent = new Intent(MainActivity.this, SoundAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Calendar fireTime = Calendar.getInstance();
fireTime.setTimeInMillis(System.currentTimeMillis());
fireTime.add(Calendar.MILLISECOND, time);
alarmManager.set(AlarmManager.RTC_WAKEUP, fireTime.getTimeInMillis(), pendingIntent);
Also, as an aside, changing the MainActivity.this to getApplicationContext() for the pending intent does not fix the crash. Saw a lot of people suggesting using one or the other, but my crash persists no matter which one I use.

I feel like it has something to do with the application context and the code not being in MainActivity or something,
Yes, you need an Activity to show a Dialog.
What you can do is build a separate Activity with the layout you want and start it from the Receiver. You can add the following code to the <activity> tag of your manifest.xml to make it appear as a Dialog.
android:theme="#android:style/Theme.Dialog"
From the Docs
Note: Activities provide a facility to manage the creation, saving and restoring of dialogs.

Related

How to display an alert box using Alarm Manager and BroadcastReceiver

I want my android app to pop-up an alert dialog box at specific time of each day. Of what I have understood is that we need to use Alarm manager to set the time of the day on repeating, and then send a broadcast to display the alert dialog box. The alert box should be displayed at the specified time even if the app is closed. I have tried the following code but it does not do anything at the specified time. Please suggest what needs to be done. I am new to android development and this is my very first implementation.
Main_Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,Calendar.MONTH,Calendar.DAY_OF_MONTH,6, 10);
setAlarm(calendar.getTimeInMillis());
}
private void setAlarm(long timeInMillis) {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertBox.class);
PendingIntent penIntent = PendingIntent.getBroadcast(this,0,intent,0);
am.setRepeating(AlarmManager.RTC_WAKEUP,timeInMillis,AlarmManager.INTERVAL_DAY,penIntent);
//Toast.makeText(this,"Alarm is set",Toast.LENGTH_SHORT).show();
}
AlertBox
#Override
public void onReceive(Context context, Intent intent) {
DisplayAlertBox(context, "Tip of the Day");
}
private void DisplayAlertBox(Context context, String msg) {
Toast.makeText(context, "Dialog Box should display Now", Toast.LENGTH_LONG).show();
PendingIntent alertBox = PendingIntent.getActivity(context,0, new Intent(context,MainActivity.class),0);
AlertDialog.Builder aBuilder = new AlertDialog.Builder(context);
aBuilder.setTitle("Message");
aBuilder.setMessage(msg);
aBuilder.setPositiveButton("Accept",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int whichButton)
{
}});
aBuilder.create();
aBuilder.show();
}
The reason why nothing is happening is because you don't have a clear understanding of BroadcastReceiver.
BroadcastReceivers, once registered, will sit there waiting for a broadcast that it can receive. Registering a BroadcastReceiver can be done in both your Manifest file or through your code. The broadcast that it can wait to receive can be either an implicit or explicit broadcast. But in your case, it's an explicit broadcast. So you would declare it in your Manifest like so:
<receiver android:name="com.package.AlertBox">
<intent-filter>
<action android:name="can.be.any.name.like.tip.of.the.day"
</intent-filter>
</receiver>
You may also register the BroadcastReceiver through code if you don't want to do so through the Manifest.
Your problem is that the intent that you're sending to your AlarmManager is Intent intent = new Intent(this, AlertBox.class). What this does is that it's only going to start your BroadcastReceiver, which isn't necessary once it's already registered. It's onReceive() is never called this way.
Your AlertBox will only show the AlertDialog when onReceive() is called, but onReceive is never called because a BroadcastReceiver's onReceive is only called when it receives the broadcast it's registered to receive.
So your setAlarm() method should be written like this:
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("can.be.any.name.like.tip.of.the.day");
PendingIntent penIntent = PendingIntent.getBroadcast(this,0,intent,0);
am.setRepeating(AlarmManager.RTC_WAKEUP, timeInMillis, AlarmManager.INTERVAL_DAY, penIntent);
Keep in mind that the String that's used as the action of the Intent must match the String that your Broadcast Receiver is listening to. This way, the onReceive() method will be able to trigger.
However, I should also mention that the BroadcastReceiver should not be where you run your AlertDialog. BroadcastReceivers are meant for short execution of codes and are not meant to persist for a lengthy amount of time. For that, an Activity or Service would be a better option.
You should consider having the AlarmManager launch a transparent Activity that hosts a DialogFragment instead.

How can I prevent two different alarm alert dialog that are triggered by two pending intents with different request code at same time

While creating an alarm application with multiple alarms Am using PendingIntent with different request codes and an AlarmService to display dialog .During this even before first dialog is snoozed or dismissed the second dialog pops up.How can I prevent this.
public void setAlarm() {
AlarmManager amgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, requestcode, i, PendingIntent.FLAG_CANCEL_CURRENT);
min = (amod.getHour() * 60) + amod.getMinute();
amgr.set(amgr.RTC,System.currentTimeMillis()+(min*60*1000), pi);
}
public class AlarmService extends Service {
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
playTone();
showDialog();
return START_NOT_STICKY;
}
I think you have two options to handle this:
1) Make sure that different request will not occur at the same time. This can be done by holding a list of all the request times and if a new one collides with an existing one, just delay it by X seconds (with this implementation, you are not guaranteed that there are no collisions, but their chance is reduced).
2) Postpone the display of a new dialog until the previous dialog is dismissed. To implement this, your dialog and service need to communicate. The dialog needs to be notified when a new message is pending so it can be displayed when the old dialog is dismissed & the service needs to be notified when the dialog is cleared so it would know that if a new message is requested, it can show.

Android: AlarmManager on firing correct alarms

ALREADY ANSWERED, FOR THOSE WHO HAVE THE SAME PROBLEM PLEASE REFERE TO THE BOTTOM OF THIS POST
I have this part on my app which schedules an alarm, all was working well, it scheduled the alarm correctly but there is a erratic behavior wherein sometimes, when the alarm scheduled is fired, instead of firing once, it fired several times, i know this cuz everytime an alarm fires i displayed "ALARM FIRED" on logcat, there are several ALARM FIRED on my logcat, sometimes up to 10, what im confused about is that i only scheudled that alarm once, and it fired many times. Here is Codes:
THIS IS FOR SCHEDULING MY ALARM THIS IS ON THE Helper class accessed in static way
public final static String ACTION = "com.medical.organizer.utilities.NotifyReciever";
private static NotifyReciever RECIEVER = new NotifyReciever();
public static void scheduleAlarm(Context context,String message,int rCode, long triggerTime)
{
RECIEVER = new NotifyReciever();
NotifyAlarm.TRIGGER_TIME = triggerTime;
NotifyAlarm.CONTEXT = context;
IntentFilter inFil = new IntentFilter(ACTION);
NotifyAlarm.CONTEXT.registerReceiver(RECIEVER, inFil);
Intent intent = new Intent(ACTION);
intent.putExtra("message", message);
NotifyAlarm.INTENT = intent;
NotifyAlarm.startAlarm(rCode);
}
public static void cancelAlarm(Context context, int requestCode)
{
RECIEVER = new NotifyReciever();
NotifyAlarm.CONTEXT = context;
IntentFilter inFil = new IntentFilter(ACTION);
NotifyAlarm.CONTEXT.registerReceiver(RECIEVER, inFil);
Intent intent = new Intent(ACTION);
NotifyAlarm.INTENT = intent;
//context.unregisterReceiver(RECIEVER);
NotifyAlarm.stopAlarm(requestCode);
}
THIS IS FOR THE ALARM ITSELF
public class NotifyAlarm {
public static Context CONTEXT;
public static Intent INTENT;
public static long TRIGGER_TIME;
public static void startAlarm(int requestCode)
{
AlarmManager am = (AlarmManager) CONTEXT.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(CONTEXT, requestCode, INTENT, 0);
am.set(AlarmManager.RTC_WAKEUP, TRIGGER_TIME, pendingIntent);
Log.d("AlarmCheck", "Alarm Started for the First Time, set() was called");
}
public static void stopAlarm(int requestCode)
{
AlarmManager am = (AlarmManager) CONTEXT.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(CONTEXT, requestCode, INTENT, 0);
am.cancel(pendingIntent);
Log.d("ALARMSTOP","========ALARM WAS STOPPED AT THIS POINT==========");
}
}
THIS IS FOR MY ALARM RECIEVER (BROADCAST RECIEVER)
public class NotifyReciever extends BroadcastReceiver {
private Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
Log.d("AlarmCheck","ALARM FIRED!");
AlertDialog.Builder build = new AlertDialog.Builder(context);
String message = intent.getStringExtra("message");
build.setMessage(message);
build.setCancelable(false);
build.setPositiveButton("Snooze", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//Rechedules the alarm after 25 secs time of interval is for
//testing purposes only
NotifyReciever.this.context.unregisterReceiver(NotifyReciever.this);
Helper.scheduleAlarm(NotifyReciever.this.context, s,
s.getRequestCode(),System.currentTimeMillis()+Helper.TWENTY_FIVE_SEC);
}
});
build.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//CANCELS THE ALARM
Helper.cancelAlarm(NotifyReciever.this.context, s.getRequestCode());
}
});
AlertDialog alert = build.create();
alert.show();
}
}
Note that the receivers aren't declared through XML, they are registered programatically so to support dialogs.
Consider this situation, this is where i notice that behavior always occurs, Say, i've added a schedule and scheduled the alarm # 5:00am (Current time is 4:59), so at first it fired completely fine, then i decided to rescheduled that alarm to 5:01 (Current time 5:00) then this occurs, the alarm is fired for several times. the alear dialog appears several times, have to fast click them all to cancel the dialogs, sometimes my app crashes due to too many dialogs showing up.
anyone knows how to go about this problem please do share and anybody knows how to properly schedule and fire an alarm please do share, as well as scheduling and firing multiple alarms as well as canceling them would be much appreciated. Explanation and some examples would be better.
EDIT
Legend: a colored dot on the side means that it is fired a at specific time and that was what logged on logcat, say an alarm fired # 4:00 display the one with several blue dots
EDIT THIS IS THE ANSWER
So this is what i've discovered , mine is that you have to register your reciever only once, so to avoid multiple returns from the intentFilter, which matches all intents using ur ACTION, in my case i've registered my reciever over and over again so there are already many instances of intents with the same ACTIOn thus returning multiple recievers and yeah firing multiple alarms at a specified time instead of firing only one receiver, so yeah REGISTER OONLY ONCE YOUR RECEIVER MAYBE AT A GLOBAL CLASS IF YOU DECIDE NOT TO DECLARE YOUR RECEIVER IN XML

How to raise an alert dialog from BroadcastReceiver class?

I have used a timer method in an Activity class. In that method I have an intent from Activity class to a BroadcastReceiver class.
This BroadcastReceiver class will call on every 15 minutes at background by using AlarmManager.
When I call the BroadcastReceiver class I would like to raise an AlertDialog.
public void timerMethod(){
Intent intent = new Intent(Activity.this,
BroadcastReceiverClass.class
);
PendingIntent sender = PendingIntent.getBroadcast(
QualityCallActivity.this,0, intent, 0
);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 60*1000, sender);
}
BroadcastReceiverClass.java
public void onReceive(Context context, Intent intent)
{
dialogMethod();
}
How can I raise an AlertDialog from BroadcastReceiver class from a background process?
If your activity is running when the BroadcastReceiver gets the intent you should be able to use runOnUiThread to run a method that creates an AlertDialog, e.g.:
public void onReceive(Context context, Intent intent)
{
runOnUiThread(new Runnable() {
public void run() {
AlertDialog.Builder d = new AlertDialog.Builder(MyActivity.this);
b.setMessage("This is a dialog from within a BroadcastReceiver");
b.create().show();
}
});
}
This works if you make your BroadcastReceiver an inner class to your Activity.
In short: It is not possible.
Only Activity's can create/show dialogs. In fact, this has been asked more then once:
AlertDialog in BroadcastReceiver
How can I display a dialog from an Android broadcast receiver?
Also, this would give a very bad user-experience:
If the user is not in your application (let's say he's playing a
Game) and your Dialog pops up every 15 minutes, this will be very
annoying for him.
If the user is in your application, there are several other (better
suited) ways to notify him that something has been executed.
Better suited ways
In fact, you can create/show a Toast from an BroadcastReceiver. This Toast will also bee shown when the user is not "in your application".
Also, you can send a Notification (shown in the Notification-Bar at the top of your screen) from a BroadcastReceiver. A tutorial on how to do this (it does not differ from how you do it in an Activity, except that you use the passed Context-Object from the onReceive-method).
The Notification will also be shown when the user is not "in your application" and is IMO the best solution to this problem.
1) In Activity:
public static Context ctx;
onCreate {
ctx = this;
}
public void showAlertDialog(Context context, String title, String message) {
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
// Setting Dialog Title
alertDialog.setTitle(title);
// Setting Dialog Message
alertDialog.setMessage(message);
// Setting OK Button
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Okay",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which)
{
alertDialog.dismiss();
}
});
// Showing Alert Message
alertDialog.show();
}
2) In BroadcastReceiver.onReceive:
YourActivity ac= new YourActivity ();
ac.showAlertDialog(YourActivity.ctx, "test", "test");

Help required in Alarm Application

I am new to Android. I am trying to develop an Alarm Application, which is actually a speaking clock. I just want the clock to use TextToSpeech API and speak out the greeting stuff and the current time as soon as the alarm time is ticked. The speech part is done. And now I want to implement the Alarm functionality. But Initially I am just trying to display a toast after 10 secs in order to check whether my classes are working properly. And I am not getting the desired response and I don't know why ? Following are the classes
Main Class aClockActivity
public class aClockActivity extends Activity {
/** Called when the activity is first created. */
private PendingIntent mAlarmSender;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button1 = (Button)findViewById(R.id.buttonOn);
button1.setOnClickListener(mStartAlarmListener);
Button button2 = (Button)findViewById(R.id.buttonOff);
button2.setOnClickListener(mStopAlarmListener);
}
private OnClickListener mStartAlarmListener = new OnClickListener() {
public void onClick(View v) {
// We want the alarm to go off 30 seconds from now.
//long firstTime = SystemClock.elapsedRealtime();
EditText Ehour = (EditText) findViewById(R.id.hour);
EditText Eminute = (EditText) findViewById(R.id.minute);
CharSequence CharHour = Ehour.getText();
CharSequence CharMinute = Eminute.getText();
int hour = Integer.parseInt(CharHour.toString());
int minute = Integer.parseInt(CharMinute.toString());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
// calendar.add(Calendar.MINUTE, 1);
cal.add(Calendar.SECOND, 10);
mAlarmSender = PendingIntent.getBroadcast(aClockActivity.this,
0, new Intent(aClockActivity.this, Alarm_Broadcast.class), 0);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), mAlarmSender);
// Tell the user about what we did.
Toast.makeText(aClockActivity.this, "The Alarm is Set",
Toast.LENGTH_LONG).show();
}
};
private OnClickListener mStopAlarmListener = new OnClickListener() {
public void onClick(View v) {
// And cancel the alarm.
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.cancel(mAlarmSender);
// Tell the user about what we did.
Toast.makeText(aClockActivity.this, "Setting off the alarm",
Toast.LENGTH_LONG).show();
}
};
Second Class Alarm_Broadcast
public class Alarm_Broadcast extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked", Toast.LENGTH_LONG).show();
}
}
Note: Just ignore the Edittext part in the OnClick() method, I'd use it later on.
Apart from the above problem there are few questions that I would like to ask.
1) How can I implement this app so that when the alarm is set, it can actually run as a service in the notification bar where the original AlarmClock runs. So that even if the app is closed its still running to invoke the alarm message at the right time.
2) I cannot show any Dialog box or can use TTS if the AlarmManager invokes a Class that extends either Service or BroadcastReciever.
3) I would appreciate if some one give me the idea to implement this app, I am sure there are many experts who would have gone through the same application.
Regards
Omayr
Here is some sample code i used in an alarm clock app hope it helps.
To set the alarm:
private void setAlarm(){
Context context = getApplicationContext();
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
myCal = Calendar.getInstance();
myCal.setTimeInMillis(TIME_THE_ALARM_SHOULD_GO_OFF_AS_A_LONG);
mgr.set(AlarmManager.RTC_WAKEUP, myCal.getTimeInMillis(), pi);
Log.i(myTag, "alarm set for " + myCal.getTime().toLocaleString());
Toast.makeText(getApplicationContext(),"Alarm set for " + myCal.getTime().toLocaleString(), Toast.LENGTH_LONG).show();
}
This goes in the onAlarmReceiver class:
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AlarmActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
this will start AlarmActivity whenever it needs to go off. In your case you'd put the toast and speech into the AlarmActivity.
How can I implement this app so that when the alarm is set, it can actually run as a service in the notification bar where the original AlarmClock runs. So that even if the app is closed its still running to invoke the alarm message at the right time.
Do not do this. Having a service stick around in memory 24x7 to watch a clock is a waste of RAM and will get you attacked by task killers, reducing your app's effectiveness. Please stick with AlarmManager.
I cannot show any Dialog box or can use TTS if the AlarmManager invokes a Class that extends either Service or BroadcastReciever.
Start an activity, perhaps a dialog-themed activity.
Just got the answer, whatever service, receiver, activity and etc you are using, you need to register it in your AndroidManifest.xml. Or else it wont work

Categories

Resources