I have a notification in my service which I cancel in my onDestroy. The notification immediately reappears after cancel code executes. Any clues?. I have tried all the flags combinations. No joy. Code edited for brevity is here.
public class downservice extends Service{
Notification notification;
RemoteViews contentView;
private static final int notifyid = 1;
Context context;
NotificationManager mNM;
PendingIntent cintent;
#Override
public void onCreate() {
String ns = Context.NOTIFICATION_SERVICE;
mNM = (NotificationManager)getSystemService(ns);
Intent noteintent = new Intent(this, configact.class);
cintent = PendingIntent.getActivity(this, 0, noteintent, 0);
contentView= new RemoteViews(getPackageName(), R.layout.notify);
Message msgtx=Message.obtain();
handler.sendMessage(msgtx);
}
private void showNotification(long[] data) {
notification= new Notification();
notification.contentIntent = cintent;
notification.icon=R.drawable.notify;
notification.iconLevel=x;
notification.flags|=Notification.FLAG_AUTO_CANCEL;
contentView.setImageViewResource(R.id.notifyimage, R.drawable.notifyimage);
contentView.setTextViewText(R.id.notifytext,text);
notification.contentView = contentView;
// We use a layout id because it is a unique number. We use it later to cancel.
mNM.notify(notifyid, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
mNM.cancel(notifyid);
}
private Handler handler=new Handler(){
#Override
public void handleMessage(Message msg){
Message msgtx=Message.obtain();
msgtx.arg1=1;
long [] data=getdata();
showNotification(data);
handler.sendMessageDelayed(msgtx, updaterate*1000);
}
};
The handler continues to execute even after service is destroyed and hence the notification which is in the handler loop reappears. I modified the code so that the handler loop does not continue after onDestroy(). I also implemented Handler.Callback since it is cleaner rather than the inline code.
#Override
public boolean handleMessage(Message arg0) {
switch(arg0.arg1){
case 1:
Message msgtx=Message.obtain();
msgtx.arg1=loopstatus;
long [] data=getdata();
showNotification(data);
handler.sendMessageDelayed(msgtx, updaterate*1000);
break;
case 2:
mNM.cancel(notifyid);
break;
default:
break;
}
return true;
}
Related
Instead of
stopForeground(true)
calling,
stopForeground(false)
should retain the notification as it is (without ongoing state) unless it is dismissed by user/removed programmatically.
This also should prevents notification flashing since I am not recreating the notification.
But it does not work. stopForeground(false) has the same behavior of stopForeground(true).
This is a sample project:
public class AudioTestService extends Service {
private static final String CHANNEL_ID = "TestChannel";
private static final int NOTIFICATION_ID = 14;
Notification mBuilder;
public AudioTestService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
stopForeground(true);
super.onTaskRemoved(rootIntent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent intentA = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intentA, 0);
Notification mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Titolo")
.setContentText("Descrizione")
.setContentIntent(pendingIntent)
.setOngoing(false)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build();
this.mBuilder = mBuilder;
createNotificationChannel();
startForeground(NOTIFICATION_ID, mBuilder);
return START_STICKY;
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = CHANNEL_ID;
String description = CHANNEL_ID + "Description ";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
#Override
public void onDestroy() {
stopForeground(false);
//NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, mBuilder);
super.onDestroy();
} }
The activity, easily handle the button click event:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startService = findViewById(R.id.startService);
Button stopService = findViewById(R.id.stopService);
Button stopNotification = findViewById(R.id.stopWithNotification);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
stopNotification.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startService:
ContextCompat.startForegroundService(this, new Intent(this, AudioTestService.class));
break;
case R.id.stopService:
finish();
break;
case R.id.stopWithNotification:
stopService(new Intent(this, AudioTestService.class));
break;
}
}}
If you look at the Service's onDestroy() method I set
stopForeground(false);
instead of the method onTaskRemoved() that should remove the notification when the app is cleaned from the task list.
What am I doing wrong?
Please do not mark this as duplicated, I am looking for a solution for days...
Instead of calling stopForeground(false); from onDestroy(), send a broadcast from activity (with action) for stop service. Change your onStartCommand code to check action in intent and do startForeground or stopForeground(false);
My application has a button : "Foreground". By clicking on the foreground button, a notification appears attached to a foreground service (started at the time of click). Clicking on my notification is supposed to stop my service (with a PendingIntent) to be able to be garbage collected, however, this is not the case. Android Studio tells me, that there is a reference to my Service held by a NotificationManager. The weird thing is that it only happens if I click on my notification after I closed the main activity.
My service code:
public class TestService extends IntentService {
public static final String ACTION_GO_FOREGROUND = "GO_FOREGROUND";
public static final String ACTION_DESTROY = "DESTROY";
private NotificationManagerCompat notificationManager;
public TestService() {
super("Name");
}
#Override
public void onCreate() {
super.onCreate();
notificationManager = NotificationManagerCompat.from(this);
}
#Override
public void onDestroy() {
super.onDestroy();
notificationManager.cancelAll();
notificationManager = null;
}
#Override
protected void onHandleIntent(Intent intent) {
}
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
switch (intent.getAction()) {
case ACTION_GO_FOREGROUND:
fg();
break;
case ACTION_DESTROY:
destruct();
break;
}
return START_STICKY;
}
private void destruct() {
stopForeground(true);
stopSelf();
}
private void fg() {
Intent intent = new Intent(this, TestService.class);
intent.setAction(ACTION_DESTROY);
// Create the notification.
android.support.v7.app.NotificationCompat.Builder notificationBuilder = new android.support.v7.app.NotificationCompat.Builder(this);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setTicker("Ticker");
notificationBuilder.setContentTitle("Title");
notificationBuilder.setContentText("Content text");
notificationBuilder.setContentIntent(PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
startForeground(1, notificationBuilder.build());
}
I know the code is messy, but it's just a sample. So why is there a reference to my service, but only if you close the activity and try to destroy the service?
Try removing the code from OnDestroy -
notificationManager.cancelAll();
notificationManager = null;
and place it in destruct() before calling stopSelf()
There seems to be other questions regarding cancelling ongoing notification.
However, i really look into quite a number of them and still have no solution.
SettingFragment
public class SettingFragment extends Fragment {
private Switch mSwitchNotific;
mSwitchNotific.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
Log.v(LOGTAG, "step notification on");
getContext().startService(new Intent(getContext(), UpdateStepNotificationService.class));
}else{
Log.v(LOGTAG, "step notification off");
NotificationManager notificationManager = (NotificationManager)
getContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
}
}
}
}
UpdateStepNotificationService
public class UpdateStepNotificationService extends Service {
static NotificationManager notificationManger;
StepsDBHandler stepsDBHandler;
public UpdateStepNotificationService() {}
#Override
public void onCreate() {
super.onCreate();
stepsDBHandler = new StepsDBHandler(getApplicationContext(), null, null, 0);
notificationManger = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
StickyUpdateStepNotification.NOTIFICATION_ID,
new Intent(getApplicationContext(), MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
final Notification notification = new Notification.Builder(
getApplicationContext())
.setSmallIcon(R.drawable.ic_notice)
.setContentTitle("Walksapp")
.setContentText("Now: " +Integer.toString(stepsDBHandler.getCurrentStepToday()) + " steps")
.setContentIntent(pendingIntent)
.build();
notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
new Timer().schedule(new TimerTask() {
#Override
public void run() {
notificationManger.notify(StickyUpdateStepNotification.NOTIFICATION_ID, notification);
}
}, 0, 1000);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
notificationManger.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
super.onDestroy();
}
}
UpdateStepNotificationService for repeating issue new notification with latest step count.
The notification is with FLAG_NO_CLEAR and FLAG_ONGOING_EVENT.
The only way turn on and off the notification is by switch button in SettingFragment.
Attempt:
notificationManger.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
Not working
Hope to see any input
Thanks
You will need to kill the timer otherwise it will continue updating the notification.
I have a service to show notification at a specific time and one broadcastreceiver for starting this service. When the app is started, the service is started and shows notification and shows the service in app running on the device, but sometimes in the running app service is a Restarting and the message does not display.
my service code is:
public class NotificationService extends Service {
private boolean flag=false;
public static NotificationCompat.Builder mBuilder;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Timer timer=new Timer();
final Context context=getApplicationContext();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if(CheckTime()){
//Intent intent = new Intent(context, NotificationReciver.class);
//sendBroadcast(intent);
showNotification();
}
}
},0,(1000*60));
return START_NOT_STICKY;
}
private boolean CheckTime(){
final Context context=getBaseContext();
Calendar calendar=Calendar.getInstance();
int hour=calendar.get(Calendar.HOUR_OF_DAY);
int minute=calendar.get(Calendar.MINUTE);
if(hour==16 && minute==11){
return true;
}else {
return false;
}
}
private void showNotification() {
Context context=getApplicationContext();
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Intent intent=new Intent(context, QuestionActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(context,0,intent,0);
mBuilder = new NotificationCompat.Builder(context).
setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Feelinger")
.setContentText("How are you feeling today?")
.setSound(alarmSound)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setVibrate(new long[]{300, 200, 200, 200});
android.app.NotificationManager mNotificationManager = (android.app.NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(100, mBuilder.build());
}
and BroadcastReceiver code is:
public class NotificationManager extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context,NotificationService.class));
}
How to solve this problem?
Write inside service
#Override
public int onStartCommand (Intent intent, int flags, int startId)
{
return START_NOT_STICKY;
}
I need to be able to start chronometer, then close activity, after that through notifications, back to that activity, and see the right time in chronometer.
What I've Done
A part of my Activity:
public void doClick(View target)
{
switch(target.getId())
{
case R.id.buttonStart:
{
Mchronometer.setBase(SystemClock.elapsedRealtime());
Mchronometer.start();
Intent intent = new Intent(RecentActivity.this, ChronometerService.class);
intent.putExtra("task_name",task_name);
intent.putExtra("task_id",task_id);
intent.putExtra("ellapsedTime",Mchronometer.getBase());
Log.d("base",""+Mchronometer.getBase());
startService(intent);
break;
}
case R.id.buttonStop:
{
stopService(new Intent(RecentActivity.this, ChronometerService.class));
Mchronometer.stop();
Mchronometer.setBase(SystemClock.elapsedRealtime());
break;
}
case R.id.button3:
{
break;
}
}
}
A part of my Service:
public class ChronometerService extends Service {
private ThreadGroup myThreads = new ThreadGroup("ServiceWorker");
private NotificationManager notificationMgr;
private int task_id;
private long ellapsedTime;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
String task_name =intent.getExtras().getString("task_name");
task_id =intent.getExtras().getInt("task_id");
ellapsedTime = intent.getExtras().getLong("ellapsedTime");
Log.d("servicebase",""+ellapsedTime);
displayNotificationMessage(task_name);
new Thread(myThreads, new ServiceWorker(),"ChronometerService").start();
return START_STICKY;
}
private class ServiceWorker implements Runnable {
public void run() {
}
}
#Override
public void onDestroy()
{
myThreads.interrupt();
notificationMgr.cancelAll();
super.onDestroy();
}
public IBinder onBind(Intent intent) {
return null;
}
public void displayNotificationMessage(String message){
Notification notification = new Notification(R.drawable.emo_im_winking,message,System.currentTimeMillis());
notification.flags = Notification.FLAG_NO_CLEAR;
Intent intent = new Intent(this, RecentActivity.class);
intent.putExtra("task_id", task_id);
intent.putExtra("ellapsedTime",ellapsedTime);
Log.d("servicebase1",""+Long.toString(ellapsedTime));
PendingIntent contentintent = PendingIntent.getActivity(this,0,intent,0);
notification.setLatestEventInfo(this,"ChronometerService",message,contentintent);
notificationMgr.notify(0, notification);
}
}
I tried to send a message from activity to a service, which contains elapsed information.
If I started it first on my device (after system load) it's works right, but when I launch it again. The activity receives wrong message. It receives the time of the first service launched on the device.
As you can see I also send one more variable, and activity reads it correctly.
I've found a solution to my question.
It's simple.
It's needed to use flag(PendingIntent.FLAG_UPDATE_CURRENT)
PendingIntent contentintent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
And it's work fine.