Service stops when activity is closed - java

I've read a bunch of answers pertaining to this question and they all seem to be the same:
"Run your service with START_STICKY"
"Run your service in the foreground"
"Run your service with startService and don't bind it"
I'm doing ALL of these things, and my service STILL closes and restarts every time my activity is closed.
This is NOT an IntentService.
I'm also not calling stopSelf or stopService anywhere except in onClick handlers.
Please scroll down to my update - This behavior has been confirmed to be a bug in the android OS and I have reported it to google. Click here to view the report.
Starting my service from MainActivity:
svcIntent = new Intent(getBaseContext(), MyService.class);
startService(svcIntent);
In my onStartCommand:
// Enter foreground state
String title = "Service has been started...";
String subject = "Service is running...";
String body = "Monitoring your battery usage.";
Notification notification = new Notification(R.drawable.theicon, title,
System.currentTimeMillis());
if (prefs.getBoolean("notificationSounds", true))
notification.defaults |= Notification.DEFAULT_SOUND;
else
notification.sound = null;
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, subject, body, pendIntent);
startForeground(1500, notification);
At the end of my onStartCommand:
...
// Release WakeLock
wl.release();
return START_STICKY;
UPDATE
I FIGURED OUT WHATS CAUSING IT! But I have no idea how to fix it. In my service i also use an AlarmManager inside my service to set up function calls to the service a specified time away.
// Alarm manager setup for MyService
AlarmManager AM = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
svcIntent1 = new Intent(this, AlarmReceiver.class);
prefs.edit().putInt("initialBatt", initialBatt).apply();
svcIntent1.setAction("com.myApp.servicealarm");
pendingIntent = PendingIntent.getBroadcast(this, 93, svcIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
// Set the alarm
AM.set(AlarmManager.RTC_WAKEUP, timeNow + waitTime, pendingIntent);
I noticed that if I DO NOT comment out the AM.set call to set an alarm, EVEN WITH AN EMPTY onReceive, my service is killed when the alarm goes off, after I swipe my app away in recent apps. If I comment out the set alarm call, then the service is never killed and keeps running after I close my app. What the heck?! I need this alarm for the functionality of my algorithms!!
It's very odd. As soon as the alarm goes off, my debug message does not print, and my service restarts. But the second time around, after the service restarts, the debug message does print and the program executes successfully.
I've tried this and it still happens with a normal broadcast receiver as well. I've also stripped my code down to ONLY the set alarm call from my service and the broadcast receiver, and the same thing occurs so it's not my algorithm. Apparantly if you have a foreground service that sets an alarm, when the alarm goes off your service restarts.
CLOSING
This behavior seems to be caused by a bug in the android OS so I do not expect an answer. If you'd like to see this bug for yourself, click here. I've provided a project that you can compile and reproduce the problem with.

Android kills the process when the broadcast Intent is sent (before it is received/processed in your app).
This is a nasty Android bug, as of 4.4 (API 19).
See https://code.google.com/p/android/issues/detail?id=63618&can=1&q=service%20restart%20broadcast&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
especially comments #22 and #23
Unfortunately, almost all "open" issues were marked as "obsolete" recently, with the assumption that they were all fixed in Android 5.0. There's no way for a developer to reopen an "obsolete" issue.
EDIT: Add details about foreground broadcast
Based on the information in the linked issue, it looks like adding Intent.FLAG_RECEIVER_FOREGROUND to your broadcast Intent will ensure that the the process does not get killed on the next receipt of a broadcast Intent.
To do this, add:
svcIntent1.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
to the code where you set your alarm in the AlarmManager.
Please read the comments in the linked issue for more details.

Try to run your service in separate process. Define it in your manifest like this:
<service
android:name=".path.to.service.class"
android:process=":my_service"/>

Related

Opening browser link with ACTION_VIEW not working for notification outside app

I had this piece of code that was working nicely not long ago:
Intent browserAction = new Intent(Intent.ACTION_VIEW, uri);
browserAction.setData(uri);
browserAction.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(browserAction);
It's inside onReceive of a BroadcastReceiver, to trigger the browser from a notification action (a PendingIntent that also do other things). For some reason (android update maybe) it now only works when I read the notification with my app in the foreground. If I'm outside my app and click the notification action, the browser isn't being called.
Any ideas of what may be happening and what I should check?
EDIT: If I do a PendingIntent directly from Intent.ACTION_VIEW (instead of using Intent.ACTION_VIEW inside a BroadcastReceiver) the action is fired nicely even outside the app. But I can't rely on this since my BroadcastReceiver did other things after calling the browser.
You need to use pending intent instead of simple intent. because notification only triggers pending intents usually while your app is in the background.
so, please try this code.
Intent browserAction = new Intent(Intent.ACTION_VIEW, uri);
browserAction.setData(uri);
browserAction.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Create the PendingIntent
PendingIntent notifyPendingIntent = PendingIntent.getActivity(
this, 0, browserAction, PendingIntent.FLAG_UPDATE_CURRENT
);
UPDATE
this answer will be useful for you. please refer to this.
refer this

Android foreground service notification not persistent

I have created a class which extends Service and runs as a foreground service. I would like my service notification to be persistent (i.e. not removed by swiping). However, my notification can be dismissed by swiping.
The Service documentation states: ...A foreground service must provide a notification for the status bar, which is placed under the Ongoing heading. This means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground...
I did put break points to check whether onDestroy() or stopSelf() is hit, but this is not the case. The service is running in foreground mode, but I can dismiss the notification by swiping.
I have found quite a few questions regarding the opposite case, where it was not possible to dismiss the notification after the service was stopped, but did not find any question similar to my problem.
The service is started via an Intent and initialized as follows:
#Override
public void onCreate()
{
super.onCreate();
initialize();
}
private void initialize()
{
Notification n = get_service_notification();
startForeground(10, n);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(BroadcastCodes.service_broadcast_intent_name));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
startServing();
return START_STICKY;
}
where startServing() subscribes to location updates
The notification is built like this
private Notification get_service_notification()
{
Intent intent = new Intent(this, LoginActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder b = new NotificationCompat.Builder(this);
b.setAutoCancel(false)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.app_icon)
.setTicker("some text")
.setContentTitle("some text")
.setContentText("some text")
.setContentIntent(contentIntent)
.setContentInfo("")
.setOngoing(true);
Notification res = b.build();
res.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
return res;
}
I have tried playing around with the flags and setOngoing/setAutoCancel, but the result stayed the same.
SDK versions are configured as minSdkVersion 18, targetSdkVersion 25
I would really appreciate any input regarding this issue - it might be just some stupid mistake, but I already did spend more than a few hours trying to research on my own...unfortunately to no avail.
EDIT 1
I still have not figured out the problem. I decided to try a dirty hack, but still no luck.
I made a PendingIntent and registered it via setDeleteIntent() the idea being to display a new notification once this one was dismissed by swipe. Unfortunately, I was not able to get this to work (the intent never fires when swiping).
I would also like to clarify, that the notification CAN BE swiped away, but IS NOT AFFECTED (i.e. is not deleted) by the clear-all button in the notification pane (the trash icon).
EDIT 2
As mentioned above I was not able to use setDeleteIntent() to recreate my notification when it is dismissed by swipe.
For now I settled with a workaround - my service does some periodical tasks. I am now calling
notificationManager.notify(10, service_notification);
when my task runs so that even if swiped away, my notification will be recreated after a while.
I still have a strong feeling that I just misread the documentation, since there are several notifications on my test device (Honor API23) that can not be swiped away.
EDIT 3
I have tried the same code on a different device (Lenovo API23) and the notification works as expected (can not be dismissed and can not be swiped). My problem seems to be device specific.
I made a few further tests (besides the ones mentioned in updates). I tried running various examples/tutorials from around the internet like this page here
On the Honor I was initially running my tests the notification could always be swiped, on the Lenovo and others the "ongoing" flag works as stated in the documentation, i.e. it can not be dismissed via swipe action.
To sum it up, my problem really seems to be device specific.

How to cancel alarms after app was closed

I've programmed an app with multiple alarms using the AlarmManager. I also have a method which cancels all current/pending alarms. It works well, however if the user closes the app from recents (alarms are still active, as intended), my cancel-alarms-method doesn't work anymore (the app crashes). Is there any solution to this? How can I cancel my alarms after the user has closed the app?
This is what my alarms look like:
ArrayList<PendingIntent> intentArray = new ArrayList<PendingIntent>();
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
...
Intent intent = new Intent(this, AlertReceiver.class);
Long cal = new GregorianCalendar().getTimeInMillis() + sms_in_x_minutes * 60 * 1000;
PendingIntent i1 = PendingIntent.getBroadcast(this, intent_id++, intent, 0);
am.set(AlarmManager.RTC_WAKEUP, cal, i1);
intentArray.add(i1);
This is what my cancel-method looks like:
private void cancelAlarms(){
if(intentArray.size()>0){
for(int i=0; i<intentArray.size(); i++){
am.cancel(intentArray.get(i));
}
intentArray.clear();
}
}
My guess is that intentArray and am are empty after I close the app, and the PendingIntents are not saved. But I don't know how to work around that.
Do not keep an array of Pending intents. As you correctly diagnosed, your array is empty after the app is closed which causes a crash when you are trying to access them again.
Set up ONLY the earliest alarm. Save the ID of the alarm to temp storage (e.g SharedPreferences). (If it is easier, you can also use a constant value for the ID as you now only have one alarm to think about)
When your alarm fires, you can set up the next earliest alarm as the first task that is performed.
If you want to cancel your alarm and have an ID value saved in your SharedPreferences, use this to recreate the AlarmManager and cancel the alarm. If there is no ID value then no alarms are set and no cancellation is required.
I think you should add the closing alarm method to the ondestroy method of your app, because if an user closes your app without stopping them, your method will never be called causing the crash of the app.
hope it works :)
EDIT: try to have a look at service and similar. some months ago i did use them in an android app and i remember that even if i close the app from recents, this service still worked and for closing it i had to add a method in app or to stop the process.
If i got it this should be the method you were looking for, sorry if i'm not precise but months passed and i forgot the name of the service i used, i'm just sure it was a service :)

Stay foreground using notification , How?

From docs I understand that our program goes to background when we open another_one then after a while android will call onDestroy() to take back it's resources ; But our program is kind of watcher (imagine we have a mediaplyer which playes music in backGround) and it should not be closed until int programState == 1 (There is a power button which ends the player or watcher ) . Besides I learned that we can stay foreground with "Notification" which is so cool (But I don't know how) ! Here is a notification code:
in Activity's onCreate(){
//> reading some data and define some initial values .
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification app_notfiy =addNotification();
//> still should perform somehing ?!?
}
private Notification addNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher_new)
.setContentTitle(getText(string.app_name))
.setContentText("> This is a notification !?")
.setUsesChronometer(true)
;
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
return builder.build() ;
}
But here we have 2 problems . First I don't think notification is really attached to Activity (Maybe it needs some permissions or use service not sure !? ) ! Next I want notification to resume app not restart it !? (I think it starts activity from onCreate() ) How force it back to where we were ?
I've searched alot but still couldn't find good answers about this . Any Idea ?
To achieve this you have to use a Service. Have a look at this tutorial.
You can start the service as a "foreground service", which runs in the background and will hardly ever get killed by the system.
To do this, call startForeground(id, notification).

Android notification opens last activity instead of proper activity

I'm having a bit of a problem, and having looked in many places I can't seem to find an answer.
I have a service, this service checks for notifications on a site and alerts the user of a new notification. When the user clicks this notification, it should bring them to an Activity (I'll call this CommentActivity)
However, if I click on the notification inside of the app, nothing happens. If I click on the notification outside of the app, it opens up the last activity shown before the app was closed.
Here is my code for displaying the notification:
Notice n; //Notification from site
....
Intent nIntent = new Intent(Intent.ACTION_MAIN);
nIntent.setClass(getApplicationContext(), CommentActivity.class);
nIntent.putExtra("activity_id", n.getFeedID());
nIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, nIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(FlankNotificationService.this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(n.getTitle())
.setContentText(n.getText())
.setContentInfo(arg0.getNotificationAmount() + " notification" + (arg0.getNotificationAmount() == 1 ? "." : "s."))
.setContentIntent(pIntent);
Notification mm = mBuilder.getNotification();
mm.flags = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL;
mm.tickerText = n.getText();
....
mNM.notify(1558, mm);
So instead of opening up the CommentActivity, it will either resume the app (if the app is not opened) or do nothing (if the app is opened)
Thank you.
Edit 1:
Added Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag to Intent. Still does not fix the problem.
Edit 2:
I found the cause of my problem (which was a rather silly cause). When the CommentActivity starts, if it does not get passed any data from either the savedInstance or the Intent.getExtra, then it will just close out. The reason why I did not think of this at first was because it didn't even show the transition. After fixing the Intent.getExtra problem it now works. Thank you for all the answers.
You may want to add the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag to your Intent. This will ensure that the CommentActivity is the resumed and active Activity when the intent is handled.

Categories