How To give notifications on android on specific time?
I want to give notification to my app on a specific time. Say everyday i have to give notification on 7 AM even if the app is closed.
How can i do this? Any tutorial? Please mention the link.
Solution 1:
first you need to use a broadcastreceiver. and because a broadcast receiver up only for a short time
from the android developer blog.When handling a broadcast, the application is given a fixed set of time (currently 10 seconds) in which to do its work. If it doesn't complete in that time, the application is considered to be misbehaving, and its process immediately tossed into the background state to be killed for memory if needed.
its a better practice to use also intent service here you have a example how to do it.
this is the broadcast receiver class.
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MyNewIntentService.class);
context.startService(intent1);
}
}
and register it in the manifest.
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false" >
</receiver>
this is the intent service class.
public class MyNewIntentService extends IntentService {
private static final int NOTIFICATION_ID = 3;
public MyNewIntentService() {
super("MyNewIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("My Title");
builder.setContentText("This is the Body");
builder.setSmallIcon(R.drawable.whatever);
Intent notifyIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//to be able to launch your activity from the notification
builder.setContentIntent(pendingIntent);
Notification notificationCompat = builder.build();
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
managerCompat.notify(NOTIFICATION_ID, notificationCompat);
}
}
and register it in the manifest.
<service
android:name=".MyNewIntentService"
android:exported="false" >
</service>
and then in your activity set the alarm manger to start the broadcast receiver at a specific time and use AlarmManager setRepeating method to repeat it this example bellow will repeat it every day.
Intent notifyIntent = new Intent(this,MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(context, NOTIFICATION_REMINDER_NIGHT, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000 * 60 * 60 * 24, pendingIntent);
i hope this will help you.
Solution 2:
You can use AlarmManager
to set alarm at specified time
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("firstTime", false)) {
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 1);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("firstTime", true);
editor.apply();
}
I used SharedPreferences
to check that's not the first time to run the app and if it is, you set that alarm otherwise do nothing instead of resetting the alarm each time you start your app.
Use a BroadcastReceiver
to listen when the alarm happens
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// show toast
Toast.makeText(context, "Alarm running", Toast.LENGTH_SHORT).show();
}
}
Use another receiver to listen to device boots so that you can reset the alarm
public class DeviceBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
// on device boot compelete, reset the alarm
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 1);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
add the permission to the manifest
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
then register your receivers
<receiver android:name=".DeviceBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
Solution 3:
A solution from the accepted answer will not work properly on Android 8 Oreo (api level 26) and higher due to background service limits (https://developer.android.com/about/versions/oreo/background.html#services) and will cause an exception like this when the app is in background:
java.lang.IllegalStateException: Not allowed to start service Intent xxx: app is in background
One of the possible workarounds is using JobIntentService
:
extend your
Service
fromJobIntentService
instead ofIntentService
and useonHandleWork
method instead ofonHandleIntent
.add
android:permission="android.permission.BIND_JOB_SERVICE"
to yourService
inAndroidManifest.xml
.
Solution 4:
Here is my solution, tested on android 10. Also is compatible with all the previous versions of android.
MainActivity.class
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
....
reminderNotification();
}
public void reminderNotification()
{
NotificationUtils _notificationUtils = new NotificationUtils(this);
long _currentTime = System.currentTimeMillis();
long tenSeconds = 1000 * 10;
long _triggerReminder = _currentTime + tenSeconds; //triggers a reminder after 10 seconds.
_notificationUtils.setReminder(_triggerReminder);
}
NotificationUtils.class
public class NotificationUtils extends ContextWrapper
{
private NotificationManager _notificationManager;
private Context _context;
public NotificationUtils(Context base)
{
super(base);
_context = base;
createChannel();
}
public NotificationCompat.Builder setNotification(String title, String body)
{
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.noti_icon)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
}
private void createChannel()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, TIMELINE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
getManager().createNotificationChannel(channel);
}
}
public NotificationManager getManager()
{
if(_notificationManager == null)
{
_notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return _notificationManager;
}
public void setReminder(long timeInMillis)
{
Intent _intent = new Intent(_context, ReminderBroadcast.class);
PendingIntent _pendingIntent = PendingIntent.getBroadcast(_context, 0, _intent, 0);
AlarmManager _alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
_alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, _pendingIntent);
}
}
ReminderBroadcast.class
public class ReminderBroadcast extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
NotificationUtils _notificationUtils = new NotificationUtils(context);
NotificationCompat.Builder _builder = _notificationUtils.setNotification("Testing", "Testing notification system");
_notificationUtils.getManager().notify(101, _builder.build());
}
}
AndroidManifest.xml
<application>
...
<receiver android:name=".custom.ReminderBroadcast"/>
</application>
NB: CHANNEL_ID
and TIMELINE_CHANNEL_NAME
, have been created on another class.
For example,
CHANNEL_ID = "notification channel"
;
TIMELINE_CHANNEL_NAME = "Timeline notification"
;
Any misconception on my code and bugs, don't hesitate to comment. I will reply as soon as possible.
Solution 5:
- Get the Alarm service from the system.
- Make a pending intent, passing in the broadcast receiver class's name.
- Make a calendar object and set the time of it too 8 am.
- Check if the current time is past 8. If yes then add another day to it.
- Call the set repeating method of AlarmManager class.
Sample code for the same:
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmIntent = new Intent(context of current file, AlarmReceiver1.class);
AlarmReceiver1 = broadcast receiver
pendingIntent = PendingIntent.getBroadcast( Menu.this, 0, alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmIntent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
alarmManager.cancel(pendingIntent);
Calendar alarmStartTime = Calendar.getInstance();
Calendar now = Calendar.getInstance();
alarmStartTime.set(Calendar.HOUR_OF_DAY, 8);
alarmStartTime.set(Calendar.MINUTE, 00);
alarmStartTime.set(Calendar.SECOND, 0);
if (now.after(alarmStartTime)) {
Log.d("Hey","Added a day");
alarmStartTime.add(Calendar.DATE, 1);
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
alarmStartTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.d("Alarm","Alarms set for everyday 8 am.");
Coming to the broadcast receiver class. You need to register your broadcast receiver in the manifest. This will cause you to receive clock events. Override the onReceive method of this broadcast receiver and make a notification there itself or make a seperate notification building service and build and display your notification there.
The manifest code snippet:
The broadcast receiver code snippet:
public class AlarmReceiver1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service1 = new Intent(context, NotificationService1.class);
service1.setData((Uri.parse("custom://"+System.currentTimeMillis())));
context.startService(service1);
}
Notification building service code snippet:
public class NotificationService1 extends IntentService{
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1;
Notification notification;
@Override
protected void onHandleIntent(Intent intent) {
Context context = this.getApplicationContext();
notificationManager =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, Activity to be opened after clicking on the
notif);
Bundle bundle = new Bundle();
bundle.putString("test", "test");
mIntent.putExtras(bundle);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Resources res = this.getResources();
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
notification = new NotificationCompat.Builder(this)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
.setTicker("ticker value")
.setAutoCancel(true)
.setPriority(8)
.setSound(soundUri)
.setContentTitle("Notif title")
.setContentText("Text").build();
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.ledARGB = 0xFFFFA500;
notification.ledOnMS = 800;
notification.ledOffMS = 1000;
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification);
Log.i("notif","Notifications sent.");
}
}