Search code examples
androidandroid-activityandroid-broadcastandroid-alarms

broadcast reciever when app is closed


I want to make an alarm clock which running even if the app is closed, everything is working fine when the app isn't closed, but when trigger the time and close the app, the moment the time goes off the app crashes. I tried few solutions but they didn't help.

here is my code:

public class MainActivity extends Activity {

//used for register alarm manager
PendingIntent pendingIntent;
//used to store running alarmmanager instance
AlarmManager alarmManager;
//Callback function for Alarmmanager event
BroadcastReceiver mReceiver;

TimePicker tp; 
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Register AlarmManager Broadcast receive.
    RegisterAlarmBroadcast();

    tp = (TimePicker)findViewById(R.id.timePicker1);
    tp.setIs24HourView(true);

    Calendar cal=Calendar.getInstance(); 
    tp.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
    tp.setCurrentMinute(cal.get(Calendar.MINUTE) );

}

public void onClickSetAlarm(View v)
{
    //Get the current time and set alarm after 10 seconds from current time
    // so here we get   
    Calendar time = Calendar.getInstance();
    time.set(Calendar.HOUR_OF_DAY, tp.getCurrentHour());
    time.set(Calendar.MINUTE, tp.getCurrentMinute());
    time.set(Calendar.SECOND, 0);

    alarmManager.set( AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent);
    tp.setEnabled(false);
//  alarmManager.set( AlarmManager.RTC_WAKEUP, 
//          System.currentTimeMillis()  + Integer.parseInt(time.getText().toString() ) * 1000 , pendingIntent );
}

private void RegisterAlarmBroadcast()
{
    //  Log.i("Alarm Example:RegisterAlarmBroadcast()", "Going to register Intent.RegisterAlramBroadcast");

    //This is the call back function(BroadcastReceiver) which will be call when your 
    //alarm time will reached.
    mReceiver = new BroadcastReceiver()
    {
        private static final String TAG = "Alarm Example Receiver";
        @Override
        public void onReceive(Context context, Intent intent)
        {
            //Log.i(TAG,"BroadcastReceiver::OnReceive() >>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            Toast.makeText(context, "Congrats!. Your Alarm time has been reached", Toast.LENGTH_LONG).show();
            tp.setEnabled(true);

             // define sound URI, the sound to be played when there's a notification
            Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

            // intent triggered, you can add other intent for other actions

            PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent("MY_ALARM_NOTIFICATION").setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);

            // this is it, we'll build the notification!
            // in the addAction method, if you don't want any icon, just set the first param to 0
            Notification mNotification = new Notification.Builder(MainActivity.this)

                .setContentTitle("New Post!")
                .setContentText("Here's an awesome update for you!")
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(pIntent)
                .setSound(soundUri)

              //  .addAction(R.drawable.ninja, "View", pIntent)
                .addAction(0, "Remind", pIntent)
                .build();

            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

            // If you want to hide the notification after it was selected, do the code below
            // myNotification.flags |= Notification.FLAG_AUTO_CANCEL;

            notificationManager.notify(0, mNotification);
        }
    };

    // register the alarm broadcast here
    registerReceiver(mReceiver, new IntentFilter("MY_ALARM_NOTIFICATION") );
    pendingIntent = PendingIntent.getBroadcast( this, 123456789, new Intent("MY_ALARM_NOTIFICATION").setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),0 );
    alarmManager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
   }
}
private void UnregisterAlarmBroadcast()
{
    alarmManager.cancel(pendingIntent); 
    getBaseContext().unregisterReceiver(mReceiver);
}
 @Override
protected void onDestroy() {
    unregisterReceiver(mReceiver);
    super.onDestroy();
  } 
}

Any kind of help would be appreciated.

and here is my manifest.xml:

<receiver android:name=".MainActivity" >

         <intent-filter>
            <action android:name="MY_ALARM_NOTIFICATION" />
        </intent-filter>

    </receiver>

Solution

  • You've defined your Activity as a <receiver> in the manifest. That can't work.

    You've got several problems here.

    1. Your BroadcastReceiver must be declared in the manifest with the <receiver> tag. This means that the class you are using as a BroadcastReceiver must be public.
    2. In your code, you've declared your BroadcastReceiver as an anonymous class. In general this will work, but this cannot work if the BroadcastReceiver needs to be called from components outside your app. AlarmMnagerruns outside of your app (indeed it will even trigger alarms when your app is not running), therefore your BroadcastReceiver must be defined as a public class that extends BroadcastReceiver.
    3. You are calling PendingIntent.getActivity(). If you want to start a BroadcastReceiver then you need to call PendingIntent.getBroadcast() instead.
    4. In your onReceive() method, you are making use of member variables that will be null in the case where the alarm was triggered while your app is not running. Since the AlarmManager can trigger the alarm even if your app is not running, you cannot expect that any member variables have been set up when onReceive() is called.

    I'd suggest that you look at some examples of how to do this. There are tons of them available.