I created a notification to be fired with a delay, done with Handler.postdelay
Now I want my user to be able to stop the running handler process somewhere between those 30 seconds:
handler.postDelayed(new Runnable () {
public void run() {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(Inlopen.this)
.setSmallIcon(R.drawable.iconsmall)
.setContentTitle("U moet uw voeten controleren!")
.setContentText("Uw moet uw voeten controleren!");
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(alarmSound);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, mBuilder.build());
}
}, 30000 );
How to do this?
I already searched a lot, but I couldn't find out how to do it with this..
You can use Handler.removeCallbacks(Runnable). The best option would be to create a constant Runnable object and provide it when using Handler.postDelayed(Runnable, long) as you will then be able to remove said Runnable specifically from the queue.
// create the Runnable object
private final static Runnable NOTIF = new Runnable() {
#Override
public void run() {
// TODO notification code goes here...
};
};
// then use it
handler.removeCallbacks(NOTIF); // to remove any posts of NOTIF
handler.postDelayed(NOTIF, 30000); // to post NOTIF with a delay of 30 seconds
you have to call handler.removeCallbacks(null). This way all the queued runnbable will be removed
Related
I am creating an app that has a constant notification that reports stats to the user. Every 10 minute, I update the stats in the app, then update the notification. The problem is, the stats update in the app, but the notification does not update until I open the app. I call the same method to update the notification regardless of if the app is open or if it is called through a service.
Is there something special I have to do because it's running through a service?
Service Code (again, this works fine):
Thread.sleep(((10 /* minutes */) * 60 * 1000));
Handler handler = new Handler(getApplicationContext().getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
OverviewFragment.refresh(getApplicationContext());
}
};
handler.post(runnable);
System.out.println("Updated values through service.");
Refresh Code (for notification):
builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher_white)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher_old))
.setAutoCancel(false)
.setContent(remoteViews)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_MAX);
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
builder.setOngoing(true);
notificationManager.notify(notificationId, builder.build());
I'm running a Handler to show some notifications in the background. While testing, when I set the delay limit to 5 seconds it works perfectly. But whenever I set it to 60 seconds or more it doesn't work. Why is that?
int delay = 1000 * 60;
HandlerThread hThread = new HandlerThread("HandlerThread");
hThread.start();
Handler handler = new Handler(hThread.getLooper());
Runnable task = new Runnable() {
#Override
public void run() {
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Intent launchIntent = new Intent(getApplicationContext(), AndroidLauncher.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, launchIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidLauncher.this);
//Set notification information
builder.setSmallIcon(R.drawable.ic_launcher)
.setTicker("Hi!")
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setContentTitle(mytitle)
.setContentText(mytext)
.setContentIntent(contentIntent);
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(builder);
style.setSummaryText("4 Task");
style.addLine("Two");
style.addLine("Three");
style.addLine("Four");
style.addLine("Five");
Notification note = style.build();
manager.notify(50, note);
}
};
handler.postDelayed(task, delay);
Import import android.os.Handler;
and use following piece of code :
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do your work here after 60 second
}
},60000);
There is good tutorial about Handler, HandlerThread, Looper here.
What i want: To run a background service that would communicate with our server via RESTFUL webservice after regular interval of 1 minute (Its a strict project requirement. So cannot increase it.)
What i have: I tried various approaches using simple BroadcastReceivers with a simple Service AND WakefulBroadcastReceivers using WakefulIntentService etc..
Main Problem: The main issue is when device screen is ON, everything is working fine on regular/fixed intervals but when the screen goes off OR devices gets locked, then the alarm Manager triggers service with a minimum interval of 5 Minutes.. Thats exactly what i dont want. I want the same 1 minute interval while device is locked/screen off.
Below is my code:
Manifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name=".MyScheduledReceiver" />
<service android:name=".BackgroundService" />
Activity.java
MyScheduledReceiver.scheduleAlarms(MainActivity.this);
gradle
// Background long running process
compile 'com.commonsware.cwac:wakeful:1.0.+'
repositories {
maven {
url "https://s3.amazonaws.com/repo.commonsware.com"
}
}
BroadcastReceiver
public class MyScheduledReceiver extends WakefulBroadcastReceiver {
private static final int PERIOD = 60 * 1000;
private static final int INITIAL_DELAY = 2000; // 5 seconds
#Override
public void onReceive(Context context, Intent i) {
try {
if (i.getAction() == null) {
WakefulIntentService.sendWakefulWork(context, BackgroundService.class);
} else {
scheduleAlarms(context);
}
} catch (Exception e) {
e.printStackTrace();
}
}
static void scheduleAlarms(Context ctxt) {
AlarmManager mgr = (AlarmManager) ctxt.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctxt, MyScheduledReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(ctxt, 0, i, 0);
mgr.setRepeating(AlarmManager.RTC_WAKEUP, INITIAL_DELAY, PERIOD, pi);
}
}
BackgroundService
public class BackgroundService extends WakefulIntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void doWakefulWork(Intent intent) {
sendNotification("HELLOO");
stopSelf();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
MyScheduledReceiver.scheduleAlarms(BackgroundService.this);
super.onTaskRemoved(rootIntent);
}
private void sendNotification(String message) {
try {
Intent intent = intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification notification;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
notification = notificationBuilder.build();
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Currently i am simply showing a notification with a sound in the notification bar from my BackgroundService.
I would really appreciate your help. Thanks !
What you want is not supported on Android 6.0 anyway. Android 6.0 will not issue alarms every minute, to any application, thanks to Doze mode.
The closest thing that will work is:
Have a service that uses a ScheduledExecutorService to get control every minute to do your work
Have that service acquire a WakeLock and keep the CPU on all the time
Have that service use startForeground() and START_STICKY to minimize the amount of time that it is not around and therefore incapable of doing this work
Make sure that application is added to the "ignore battery optimizations" whitelist in Settings
Ignore the cries of anguish from users, complaining that their battery life is atrocious
Try using like this
public static void scheduleAlarms(Context ctxt) {
AlarmManager mgr = (AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctxt, MyScheduledReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(ctxt,REQUEST_CODE, i, 0);
// We want the alarm to go off 3 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
firstTime += 3 * 1000;//start 3 seconds after first register.
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime,
600000, sender);//10min interval
}
Have you tried using a Handler to obtain this goal? AlarmManager will typically work on a battery friendly rhythm when possible. Whereas Handlers are much more exact.
For example, you could run this code in your Service:
// Store this as a member variable
private Handler mHandler = new Handler();
// This can be a member variable or local
private Runnable runnable = new Runnable() {
#Override
public void run() {
// Do stuff
// Tell the Handler to call itself again
mHandler.postDelayed(this, 60000);
}
};
// Put this at the start of `Service`
mHandler.postDelayed(runnable, 60000);
As Commonsware points out, having the Handler declared as it is above would cause the Handler to run on the Main Thread. Here is some documentation on how to get a Handler to run in the background:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
how can i create a notification in the notifications bar that disappear after 5 seconds?
For example; this is the notification code:
Intent intent = new Intent(this, NotificationReceiver.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notification
// Actions are just fake
Notification noti = new Notification.Builder(this)
.setContentTitle("Notification")
.setContentText("This is a notification that didsappears in 5 seconds")
.setSmallIcon(R.drawable.icon)
.setContentIntent(pIntent)
.addAction(R.drawable.icon)
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, noti);
Starting from this code how can i create my notification that disappear after 5 seconds?
You can simply cancel your notification after 5 seconds.For this you can use either Timer or Handler.Here is Handler solution:
Handler handler = new Handler();
long delayInMilliseconds = 5000;
handler.postDelayed(new Runnable() {
public void run() {
notificationManager.cancel(YourNotificationId);
}}, delayInMilliseconds);
if you want to use Timer instead of Handler. Then you can try:
Timer timer = new Timer();
timer.schedule(new TimerTask()
{
public void run()
{
notificationManager.cancel(YourNotificationId);
}},delayInMilliseconds);
}
You can use method cancel(int id) or cancelAll() to dismiss your notifications.
Start a timer for 5 seconds and when it ends call cancell();
http://developer.android.com/reference/android/app/NotificationManager.html#cancel(int)
Is it possible to make a notification automatically disappear after a period of time?
You can use the AlarmManager. I think is more appropriate and more easier to implement than an Android Service.
With AlarmManager you do not need worry about make something running until the time finish. Android do that for you, and send a brodcast when it happen. Your application must have a Receiver to get the correct intent.
Look theses examples:
Android: How to use AlarmManager
Alarm Manager Example
Now there is an option called .setTimeoutAfter(long durationMs)
https://developer.android.com/reference/android/app/Notification.Builder.html#setTimeoutAfter(long)
Yeah, you can just create a service that runs in the background that'll timeout after five minutes and delete your notification. Whether you "should" actually do that is up for debate. A notification should be there to notify the user... and the user should be able to dismiss it on their own.
From d.android.com:
A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
Yeah, it is very easy.
Where you get notification there add one handler if notification is not read by user then remove notification.
#Override
public void onMessageReceived(RemoteMessage message) {
sendNotification(message.getData().toString);
}
add notification code
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("TEST NOTIFICATION")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int id = 0;
notificationManager.notify(id, notificationBuilder.build());
removeNotification(id);
}
cancel notification code.
private void removeNotification(int id) {
Handler handler = new Handler();
long delayInMilliseconds = 20000;
handler.postDelayed(new Runnable() {
public void run() {
notificationManager.cancel(id);
}
}, delayInMilliseconds);
}
You could also use a classic Java Runnable for a simple small Thread.
Handler h = new Handler();
long delayInMilliseconds = 5000;
h.postDelayed(new Runnable() {
public void run() {
mNotificationManager.cancel(id);
}
}, delayInMilliseconds);
Also look here:
Clearing notification after a few seconds