There are several questions about it but I always read the same thing: "the service will be killed if the system need resources" or "you can't build an service that runs forever because the more it runs in background, more susceptible it is to the system kills it" and etc.
The problem I'm facing is: My service runs fine and as it is expected, if I run my app then exit it my service is still running, but when I kill my app (by going to the "recent apps" and swype it away) the service stops. In this moment, if I go to the Settings >> aplications >> running I'll see that the service is restarting. After a while, it goes back and my Service run with no problem.
I google it and I find some things I could do but lets see my code first:
I start my service by this way (after a button click):
Intent intent = new Intent (MainActivity.this, MyService.class);
startService(intent);
I also have 3 Integers I put in extra, so I have something like this:
final Integer i, i2, i3;
i = 5; //for example
i2 = 10; //for example
i3 = 15; //for example
final Intent intent = new Intent (MainActivity.this, MyService.class);
intent.putExtra("INTEGER1", i);
intent.putExtra("INTEGER2", i2);
intent.putExtra("INTEGER3", i3);
startService(intent);
In MyService I have the folloywing:
public class MyService extends Service
{
AlarmManager am;
BroadcastReceiver br;
PendingIntent pi;
Integer i, i2, i3;
#Override
public void onCreate()
{
super.onCreate();
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros?
br = new BroadcastReceiver ()
{
public void onReceive (Context context, Intent i) {
new thread(new Runnable()
{
public void run()
{
//do something
}
}).start();
}
};
}
#Override
public void onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
try
{
i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here
i2 = intent.getIntExtra("INTENT2", 0)
i3 = intent.getIntExtra("INTENT3", 0);
}
catch(NullPointerException e) {}
this.registerReceiver(br, new IntentFilter("anyany"));
new thread(new Runnable()
{
public void run()
{
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock. elapsedRealtime() + i*1000, i2*1000, pi);
}
}).start();
return START_REDELIVER_INTENT; //so I can get my Extra even with my Activity closed
}
My onDestroy:
#Override
public void onDestroy()
{
unregisterReceiver(br);
super.onDestroy();
}
I also have onBind() method (without #Override), but it returns null.
I google a lot and I tried to run the service in foreground, so I did this (inside de onStartCommand):
Notification n = new Notification(R.drawable.ic_laucher), getText(R.string.app_name), System.currentTimeMillis());
PendingIntent npi = PendingIntent.getActivity(this, MainActivity.class);
n.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), npi);
startForeground(3563, n);
My notification appears and when I click on it my app runs, but the problem with my service wasn't fixed (I believe it still not run on foreground). The notification is restarted too.
I also deleted the Try catch and I define a value for the integers (so I didn't use the getIntExtra() method), but nothing changed
After several tests I tried to see the logs, when I kill my App I have the following message: Scheduling restart of crashed service.
So, for some reason my service crash when my MainActivity dies, why? The intention here is not to transform the service in a god that can not be killed (I don't think it is impossible at all, the WhatsApp are running for 105 hours !) but prevent my Service to not being crashed after my App dies.
I don't know if this'll help but this is what I add on my Manifest.xml
<Activity android:name = ".MyService"/>
<service android:name ="Myservice" android:enabled="true" android: exported="false"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Min API = 9, target API = 17.
Size of the Service when running: about 3MB.
Hope I was clear and sorry for my English.
PS: the entire code are running as expected, so if you see any sintax error fell free to edit it.
EDIT
If I add android:isolatedProcess="true" in the <service> in AndroidManifest.xml I receive this error in logCat: java.lang.RuntimeException: Unable to create a service in com.mycompany.myapp.myservice: java.lang.SecurityException: Isolated process not allow ed to call getIntentSender
When I start my service using this, the MainActivity does not show any erros, only the service crashes.
I finally found the solution ! I removed the AlarmManager from the Service and the service does not cashed anymore, but I have to use it
The problem is the service crash after the user swype away the app from Recent App, so what I did was prevent the app to appear in that window. Add the following to your AndroidManifest.xml as a child of <activity>
android:excludeFromRecents="true"
Now when the user exit from your app it wil not appear in the recent apps window, what means the system kills the Activity right after you exit it, so it'll not waste any resources.
PS: don't forget to set the service to run in a separate process, add the following to your AndroidManifest.xml, as a child of <service>
android:process=":remote"
EDIT - REAL SOLUTION FOUND
After a lot of research and study (months of study) I took a deep look at android APIs and here is what a found, this is na expected behaviour that occours only at API 16+, a change at android arquiteture changed the way that PendingIntents are broadcasted by the system, so Google added the flag FLAG_RECEIVER_FOREGROUND, you must pass this flag to the intent you are using as a parameter on the PendingIntent.getBroadcast(), here is na example:
if(Build.VERSION.SDK_INT >= 16) //The flag we used here was only added at API 16
myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;
PendingIntent pi = PendingIntent.getBroadcast(context, 1, myIntent, 0); // the requestCode must be different from 0, in this case I used 1;
Android versions older than API 16 will work as expected, the service won't crash if you swype away the app from Recent Apps page.
As the documentation says, a Service runs in the main thread of its callee, that usually is the UI Thread. So what is happening is that when you kill your application, you kill your application process and thus the service is killed too.
You can workaround this behavior by creating your Service in a different process by using android:process in your <service> tag in the Manifest.xml file.
Usually, though, you start a Service in its own process if the Service needs to be independent from the callee and if it may be used by different application. If your Service is for your own application use only, then stick with the default behavior and simply don't kill you application.
EDIT 1:
The documentation for android:isolatedProcess says:
If set to true, this service will run under a special process that is
isolated from the rest of the system and has no permissions of its
own. The only communication with it is through the Service API
(binding and starting).
From another SO answer (Link), this is the expected behavior. But surely, someone here will have a workaround or a solution.
Your questions from code:
pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0)
//Why those zeros?
The first zero you see is mentioned as a requesCode and decribed as not being used presently:
requestCode: Private request code for the sender (currently not used).
The second zero should actually be one of the flags given (here).
i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why
this zero are here
The getIntExtra(String, int) method of Intent doesn't need to have 0 as its second argument: it can be any integer. getIntExtra(String, int) returns an integer corresponding to the String key you provide. In the event that this key no long exists(or never did), getIntExtra(String, int) returns the integer we pass as the second argument. It is the default value when the key fails.
Related
(Before you mark this question duplicate, please note that I'm facing this problem in a specific API Level (API R), the app shows normal expected working behaviour on other API levels below R).
When running the app on Pixed 3a API R
I'm trying out the the Alarm Manager in android, by building a basic Alarm app. I have an AlarmPageActivity that I tried to start from my custom Broadcast Receiver (AlarmReceiver.java)
I have code in my MainActivity where I set the alarm using Alarm Manager. When the alarm goes off, the pending intent goes to the AlarmReceiver class where I try to start an activity using context.startActivity(context, alarmIntent).
The problem: [Before you go there, yes I have the appropriate flags required (Intent.FLAG_ACTIVITY_NEW_TASK)]. When I set a time for the alarm, and keep the app open, the AlarmPageActivity (the activity which is supposed to pop open when the alarm goes off) launches and the app executes normal behaviour. But when I set a time, and close the app (onDestroy()), the code follows through to AlarmReceiver.java (my Broadcast receiver), the ringtone starts playing, but my AlarmPageActivity doesn't show up (In fact, even it's onCreate() method does not execute). Neither does it show any error in the Log/run window. I tried changing everything from pending intent parameters, to adding new activity flags to the intent object, etc. but nothing worked! You can see below in the code that there is no syntax error that should be stopping the code from starting a new activity through broadcast receiver (when the user is outside the app).
I faced this issue for nearly 2 days. I read every article/post on the internet about starting an activity from a broadcast receiver class. But it wouldn't work, and I got so frustrated. Then MIRACULOUSLY, I thought why not try running the app on a different emulator. And guess what? it worked. sigh... I kept thinking I was doing something wrong or that my code was whack because I'm only so beginner-ish in android studio. But little did I know, that my code was correct all that time.
When running the app on Pixed 3a API 26
The app shows normal expected behaviour. Even after onDestroy(), the BroadCast receiver receives and launches the AlarmPageActivity, with the ringtone :)
My Question: This is the same code (I didn't change/add anything else) that was not working on the emulator device running API R, but works now in API 26. Can somebody explain why it wouldn't work? I would really appreciate. Or maybe my code wasn't compatible with API R in some way... who knows? Enlighten me!
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
...
other code...
...
// Alarm manager code ----------------------------------------
alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 56);
calendar.set(Calendar.SECOND, 0);
long startTime = calendar.getTimeInMillis();
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
final PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(this, 0,
alarmIntent, 0);
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startTime, alarmPendingIntent);
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.d("asdfasdf", "BroadcastReceiver (alarmReceiver) activity reached");
Intent alarmIntent = new Intent(context.getApplicationContext(), AlarmPageActivity.class);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmIntent);
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
// ringtone code ...
ringtone.play();
Log.d("asdfasdf", "Reached end of alarmReceiver ");
}
} // mind the wrong indenting here
AlarmPageActivity.java
has the default empty activity code...
And yes, I know I shouldn't run an activity from a Broadcast receiver as it shouldn't do heavy task that takes > 10s and everything, but I just wanted to see how to it would look like before improving on that code later.
I think it not work from android 10 and higher. Please read more detail about Restrictions on starting activities from the background. Try to request permisison SYSTEM_ALERT_WINDOW for this case
it kills background service, to solve your issue you should use foreground service.
my background sticky service is kill on oreo and heigher devices any solution for getting location on background service when Activity is on backound
It's because of Android Oreo behaviour changes for background execution. Suggested alternatives are
1) Foreground service.
Use this if you are ok displaying notification to the user when you are trying to retrieve the location using Location API. This would be reliable and is suggested in the documentation.
Sample app from the documentation :
LocationUpdatesForegroundService project on GitHub
An example of an app that allows the app to continue a user-initiated
action without requesting all-the-time access to background location.
References
https://developer.android.com/training/location/receive-location-updates
2) Work Manager
This approach would be less reliable as you will not be able to control when exactly this would be called but can be used if you don't want to show notification to the user at all.
You would not be able to run background services long running in Oreo as there are behavior changes, now Oreo to optimize system memory, battery etc, it kills background service, to solve your issue you should use foreground service.
Have a look at Background execution limits https://developer.android.com/about/versions/oreo/android-8.0-changes
A suggestion from me, if you can use FCM then go for it, because apps like WeChat, Facebook uses it, to deliver notifications and they don't face any problem.
Alternate solution which I have opted without FCM due to client requirement to run service that updates location in background. Here are steps below:-
You need to start your background service with showing notification in Oreo and above.
Them after that you need to keep in mind that after some time phone enters into Doze mode so you have to tackle that also
In Addition, Battery optimization must be disabled for the application too.
In Some custom ROM you need to manage the Auto-start permission to restart your service if the service is killed by the android.
And the most important part is, if the service is killed by the android system then send a Broadcast Message to the Broadcast receiver to restart your service one again
Hope you will do some more R&D work.
I have shared my experience and the process by which i have done the same to run the service in the background.
you must show notification for ForegroundService
public class ForegroundService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and add permission
<uses-permissionandroid:name=”android.permission.FOREGROUND_SERVICE” />
I noted that when I close my app definitively, the method runInBackGround of the class MultiplyTask stops working. It works when the activity is in the phase STOP or PAUSE, but when I close my app, the method finishes ( it's a loop created with a cycle while(true) {...} ).
How can for example Whatsapp send notifications though it's closed? I want to create a similar thing. Thanks!
When the app is closed, all code will stop running. If you are looking to execute while the app is open and continue executing code while the app is closed, you will want to look into using a Service.
Take a thorough look at the Service documentation and it will hopefully be what you are looking for.
Services are also killed when your app is closed, but using the START_STICKY return value you can make sure your service is restarted upon termination.
EDIT WITH MORE INFORMATION:
<service
android:name="MyService" />
Add the above to your AndroidManifest.xml
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// This is where you would place your code that you want in the background
// Putting your while loop here will make sure it runs when the app is closed
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
}
Create a new class with the above code.
Intent i= new Intent(context, MyService.class);
startService(i);
Call this code from your launcher Activity to start the service when the app is launched.
Hope this helps!
Asynctask is ideal for short operation which are needed to be performed in the background. Usually Asyntask is implemented as sub class of activity which is destroyed when app is close. Also It communicates with the UI thread at some points ... so It needs the activity to be in memory... For long running operation, Service is better. Some Apps notify user even when they are not running. In fact they have one or more services running in background. You can see those in your phone setting->apps menu.
Study this for more information about services.
Hello I am running a background service to check in my server if there is a new data.
But if I kill the App, the background service also dies.
If I run the background service on it;s on process, the system kill it after it has run a couple times.
Manifest
<service
android:name=".backgroundSerive"
android:enabled="true"
android:exported="false"/>
Option 2
<service
android:name=".backgroundSerive"
android:process=":my_process"
android:enabled="true"
android:exported="false"/>
MainAActivity - Starting the service
Intent i = new Intent(this, backgroundSerive.class );
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(i);
Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...start runnable
return START_STICKY;
}
I try both option, The service keeps getting killed.
Any advice. To make my server always run.
thank you
You need to call startForeground() from within the service, to lower the chance of Android actually killing it. Please check out this sample for an example implementation.
startForeground function sends the service to foreground, so android system considers this operation as a foreground task. Which is very less likely to be killed.
If you have choosen the services destroy action as START_STICKY it would get destroyed but right after it destroyed it should be reinitialized with a null intent.
You may consider using Alarm for such event.
Since alarms are running in an internal process they reduce the app overhead, yet they provide recurring checks.
After a long search I'm still confused about it although I found some related posts but they were not answering what I was looking for. in my scenario I want to send user's lat long at fixed intervals like every 5 minutes to a server. to do this I used a service with its own process so that it doesn't get killed when Activity destroyed and in service method onStartCommand I used a while loop having condition of always true and in that loop I update location to server and give delay by thread.sleep like shown below
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
While(true)
{
Location currentLocation = getLocation();
updateLocationToServer(currentLocation);
try
{
Thread.sleep(300000)
}
catch(Exception e)
{
e.printStackTrace()
}
}
return Service.START_STICKY;
here I cannot understand the return statement is unreachable then how can the service will be restarted automatically when it is destroyed and secondly using thread.sleep causing ANR (Application Not Responding) while service is a background process and I found that its directly running in UI thread these information are confusing me and in this case what is the best way to get desired functionality.
You should use and AlertManager instead!
AlarmManager mgr=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(context, OnAlarmReceiver.class);
PendingIntent pi=PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), PERIOD, pi);
http://justcallmebrian.com/?p=129
secondly using thread.sleep causing ANR (Application Not Responding) while service is a background process
from
http://developer.android.com/reference/android/app/Service.html
Note that services, like other application objects, run in the main thread of their hosting process.
Try using Alarm Manager instead, see this example of how to set it to repeat every 5 minutes