In my android app, I have a Service that starts when the app goes in background. OnStartCommand begins long running task that analyzes and checks device and app status.
Now, I am preparing the app for Android O. First issue that i faced is Services, I rework them to JobServices.
Now I am facing another issue. When user removes my app from application stack JobService.OnTaskRemoved doesn't get called.
Before, when I used Service calling of Service.OnTaskRemoved worked fine for me.
Now I see only way. I need My old Service for handlingService.OnTaskRemoved and new JobServices for executing task.
Am I wrong? May be some one can give me good advice?
You are implementing the wrong concepts.., which creates problem.., To tackle it .. you are again implementing wrong things.. Please offload all...
In my android app, I have a Service that starts when the app goes in background..
The Problem ;
In android O there is no background execution allowed at all.. Even a single line of code is not guaranteed to execute..!!
And you want it to execute long running service..!!
The Solution;
The same service can be started whenever App is opened first time... On acquiring all runtime permissions. As :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, YourLongRunningService.class));
}
else
{
context.startService(new Intent(context, YourLongRunningService.class));
}
OnStartCommand begins long running task that analyzes and checks device and app status.
The Problem ;
OnStartCommand is not meant to be coded the long running procedures / statements of code..
Nor it is meant to be coded at all........
The Solution;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RUNNER : ", "\nPERFORMING....");
return START_STICKY;
}
Above single line tells android to keep alive ALL THE TIME UNTIL DEVELOPER STOPS IT ON HIS OWN VIA CODE STOPSELF Even removed from background or from recents; It gets re-created automatically by android os
Then where should i write the code.... ??
Wait... its too early to code yet....!!! patience
begins long running task that analyzes and checks device and app status
Your question is un clear and in my brain there is a gradle error ... I can not resolve your symbols :
analyzes
checks device
app status
But i know that these your broadcasts definitely .. And you need to implement broadcast-receivers... to receive it...!!
I will implement Broadcast receivers... Its too easy...
The Problem ;
Wait... Android O do not allows you to implement many broadcast receivers from static receivers like we does... And even we are not allowed to call that receivers on specific intent-actions from manifest.xml
The Solution;
Implement runtime receivers in your above created service YourLongRunningService in onCreate like :
IntentFilter myFilter = new IntentFilter();
myFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
this.registerReceiver(mCallBroadcastReceiver, CallFilter);
CONNECTIVITY_CHANGE is an example and it would be your intent action / broadcast you want to listen for...!!
What is mCallBroadcastReceiver and all...
These are runtime registration of receivers... and needed to be unregistered from onDestroy like :
#Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
super.onDestroy();
}
No.... No... No.... I do not want to un-register it... I want it always working..
Our service is START_STICKY Even if it is destroyed; gets started automatically and registers mCallBroadcastReceiver in onCreate again..
Where is the receiver then....???
In this case mCallBroadcastReceiver is receiver defined in class area where we declares the variables and constants :
public class YourLongRunningService extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// All your receiver code goes here...
}
};
// your constructor
// your onStartcommand
// your ondestroy
}
What notification Manager is doing here....???
In and above O you can not run foreground service without proper Ongoing task notification... It will go in your onCreate which will call Startforeground with the notification to start this service as a foreground service
What below android O...?
It works below Android O too... Just call with normal startservice its code it given on very start...!!
Where is my long running code goes then....???
From receiver receive broadcast you want and start a intentservice or a job or a alarm class or whatever you want...
I will make a simple class which takes context in constructor and defines a public method named LongRunningCode may be of one crore lines of code....
And on receiving broadcast in receiver , I will make a object of that class by passing context of receiver and will simply call LongRunningCode method with that object
Hope it helps
Related
I have an Android Service (implementation of Servcie interface) which is running on a separate process compared to my real app. Unfortunately when I leave my real App (in which I clicked the Button to start my Service) and swipe it out from Task Manager, my Service gets killed as well.
I know there are a lot of questions like this here, but somehow none are targeting the Problem in my concrete constellation or they are vaguely answered.
So in my manifest I have something like:
<application ...>
<activity .../>
<service Android:name="MyService"
Android:label="MyLabel"
Android:export="false"
Android:process=":MyRemoteProcessName" />
</application>
I first have played around with an IntentService, but also switched to an own implementation of the Service Interface (eliminating the IntentService to be the point of failure) which looks something like:
public class MyService extends Service {
private ScheduledExecutorService scheduledWorker = Executors.newSingleThreadScheduledExecutor();
#Override
public void onStart() {
// Init components
startForeground(this, MyNotification);
}
#Override
public int onStartCommand(Intent i, int startId) {
// Execute Work on Threadpool here
scheduledWorker.execute(new ScheduledStopRequest(this, startId), 5, TimeUnit.Minutes);
return START_REDILIVER_INTENT;
}
// Overwritten onDestroy-Method
#Override
public void onLowMemory() {
Log.e(LOG_TAG, "On Low Memory called!");
}
#Override
public IBind onBind() {
// Dont't want to let anyone bind here
return null;
}
// Simply tries to stop the service after e.g. 5 Minutes after a call
private static class MyRunnable implements Runnable {
// Constructor with params used in run method..
#Override
public void run() {
mReferenceToMyService.stopSelfResult(startId);
}
}
}
I'm starting my Service in an onClick-Listener on a special button, with an explicit Intent, which kinda looks like the following:
#Override
public void onClick(View v) {
Intent i = new Intent(this, MyService.class);
startService(i);
}
My Intention is to keep the Service running when the user leaves the app, so that the Service can finish downloading and storing some important data. When the user comes back to my app again, he can view the data (That's why I'm executing it in a separate process). So is this possible?
My assumption right now is, that Android somehow notices my Service is just being used by my App (due to missing IntentFilters in Manifest or explicit call rather than by filter?!) and thus kills it immediately when my App is closed (even when running as ForegroundService as you can see above).
Does it seem possible to you and might some changes in the call of the service fix this problem or am I getting the concept of a service wrong?
(One last note: onLowMemory-Method doesn't get called -> No log entries.)
So, according to your hints (and so new keywords for me to look for) and after some additional research by myself, I think I have solved my problem. During my research I have found an very interisting blog post on this topic, maybe also for you, which is why I would like to share it with you: http://workshop.alea.net/post/2016/06/android-service-kill/ .
After verifying and going through the steps in this article everything seems to work fine (so startForeground seems to solve the problem). I want to point out here, that I have only tested it, with my service instance still running in separate process, so manifest entries as is above.
The actual thing which really confused me at the beginning was my android studio debug session being killed everytime, just after swiping out my app from recent apps (menu). This made me think my service being killed by the system as well. But according to the article (I have added some logs to the callback methods provided) when
Opening my app
starting service
swiping out app
starting app again and finally
calling service again,
I only received callbacks to the methods as if my service would still be running. Having an explicit look at DDMS (tool) also prooved my 2nd process, and thus my service, being still alive. Having verified this, I then cleared all my app data and repeated the steps above (excluding step no. 5). Having had a look in the database afterwards, prooved the data having been downloaded by the service.
For the curious of you:
The process of swiping out my app from recent apps (and thus having the onTaskRemoved callback method being called) lead to another problem. It somehow increases the startId parameter of onStartCommand by 1 so that my DelayedStopRequest malfunctiones and doesn't stop my service anymore.
This means: Repeating above steps 1 - 3 makes me receive startId = 1 in onStartCommand. By calling stopSelfResult(1) later on (which was the latest startId) it returnes false and the service keeps running. Continuing to follow step 4 + 5 then, makes onStartCommand being called with startId = 3 (but should actually be 2! which is skipped somehow). Calling stopSelfResult(3) with parameter 3 later on is then going to stop the service again (also visible in screenshots).
I hope my answer is correct so far (, understandable) and also helpful for you. Thank you for all of your answers which provided beneficial input and also pointed me to the solution. The android version I have been working with is:
4.1.2 - Jelly Bean | API Level : 16
I also added screenshots of the log entries from DDMS (imgur is rejecting my uploads so you'll temporarily have a link to my dropbox):
screenshots from logs from DDMS
Unfortunately running service in a separate process does not help you. I think there is no way you can prevent your service from being closed if user removes its task. You can however restart your service overriding onTaskRemoved. See this answer.
If you want to run this service class indefinitely after closing the app also.. you should use Alaram Manager class ..
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(this, LocationListnerServiec.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, MyAlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
60000, pIntent);
}
Use this method for keep checking the service class is on or off.. By using this method Your service class will keep working after destroying of you application.
I am confused right now , about service concept of running and stopping:
what i want to do:
Start Location service at the very start of application.
Keep getting location updates and store them to shared preference
Stop the service in onDestroy of Application scope!
So far i have searched and studied we can only do following things with service(correct me if i'm wrong):
Stop the service automatically by binding it to related activities/fragments/views , when all of them destroyed service unbind itself automatically so we can call stopself method in unbind
return START_NOT_STICKY in onStartCommand to tell OS , don't recreate it , and create intent local service , after completion of some work it will destroy itself.
Stopping the service manually , by declaring it's intent in some kind of static scope and stopping the service in on onActivityDestroyed of Application class [I am not sure what will happen? , maybe service will destroy each time any activity will be destroyed ? or it will be destroyed only when overall application get's destroyed?]
Either way , i am bit confused and beat , been trying to adjust my Location service with given details for 2 days
If you start your Service using START_NOT_STICKY, then your app will kill your service once your entire application is closed from background i.e. you cleaned your app from home screen.
Here START_NOT_STICKY states that you need not recreate service in case it is been killed.
If this is not the case then you have to manually kill it by your self.
Like
Intent lintent = new Intent(context, LocationService.class);
context.stopService(lintent);
You can use this code at point where your application kills.
That's it. You are good to go with this.
First of all, launch the "LocationService" on your app start:
public class MyApp extends Application {
private static final String TAG = "MyApp";
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
startService(new Intent(this, MyLocationService.class));
}
}
Second :
As you said, the Service should better run with the "START_NOT_STICKY" flag
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Thrid:
Once the system kills your app, the Service will automatically be killed, so no problems at all.
There is no onDestroy() method on the Application object, the only similar event is onTerminated() and it is not being launched on production devices.
onTerminate
Added in API level 1 void onTerminate () This method is for use in
emulated process environments. It will never be called on a production
Android device, where processes are removed by simply killing them; no
user code (including this callback) is executed when doing so.
More information:
https://developer.android.com/reference/android/app/Application.html#onTerminate()
Btw, If you want the MyLocationService to send updates of the location to your app (when it is open), you should consider to use Otto or EventBus (I recommend you this last one because of the simplicity to use it). You can even configure the #Suscriber to receive updates of old retrieved locations if you want.
I will try to explain in a easiest way :)
There are two type of service
IntentService and Service
IntentService when started will kill itself once it treated the content of it onHandleIntent method
as for Service well this one will not end until you give it the command to do so even if your start it using the context of an activity. It will also stop when the application is stopped in an extreme case (by system (Settings/application/YourApp/stop app OR an app crash)
Easiest way is First of all start IntentService with AlarmManager at some repeating time (10 mintutes), then in onHandleIntent() get Location and store into preference.
No Need bind to your activity, the IntentService automatically stops itself after saved in preferences.
Yes you can stop the service in onDestroy() of the activity:
#Override
public void onDestroy(){
Log.v("SERVICE","Service killed");
service.stop();
super.onDestroy();
}
I want a service to run all the time in my application. So I want to restart it even if it is force closed by user. There is definitely a way to do it as apps like facebook are doing it. It's not done using push notification, facebook restarts its service even if internet is off.
First of all, it is really very bad pattern to run service forcefully against the user's willingness.
Anyways, you can restart it by using a BroadcastReceiver which handles the broadcast sent from onDestroy() of your service.
StickyService.java
public class StickyService extends Service
{
private static final String TAG = "StickyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("YouWillNeverKillMe"));
}
}
RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
private static final String TAG = "RestartServiceReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context.getApplicationContext(), StickyService.class));
}
}
Declare the components in manifest file:
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Start the StickyService in a Component (i.e. Application, Activity, Fragment):
startService(new Intent(this, StickyService.class));
OR
sendBroadcast(new Intent("YouWillNeverKillMe"));
You have to create a sticky service with overriding onTaskRemoved method, where you can set an alarm service to trigger your code again.
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
//create an intent that you want to start again.
Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
super.onTaskRemoved(rootIntent);
}
}
Also in some devices like Xiaomi, Huwaei the app gets force closed once it's removed from recent apps. This is because the manufacturers have task manager features which improve ram/battery performance.
You can check this link for more information: https://stackoverflow.com/a/41360159/2798289
As per the Android document
Starting from Android 3.1, the system's package manager keeps track of applications
that are in a stopped state and provides a means of controlling their launch from
background processes and other applications.
Note that an application's stopped state is not the same as an Activity's stopped
state. The system manages those two stopped states separately.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the
list of potential targets to resolve against.
FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the
list of potential targets.
When neither or both of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential targets.
Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents.
It does this to prevent broadcasts from background services from inadvertently or
unnecessarily launching components of stopped applications. A background service
or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES
flag to broadcast intents that should be allowed to activate stopped applications.
On Force stop of app, Android just kill the process ID. No warnings, callbacks are given to service/activities. As per the Android document, When the app is killed there are chances that it calls onPause().
When I tried in my app, even onPause() was not called. I think the only way is use to FLAG_INCLUDE_STOPPED_PACKAGES intent flag and send it from another app
If I understand correctly, then actually this is not possible, Android feature to force close application was designed to allow user to get rid of unwanted applications, so it disallows any activities from it until user again starts any of its Activity.
Restart the service even if app is force-stopped and Keep running service in background even after closing the app How?
Whenever a service is killed, its onDestroy method is always called.
Its better to use a BroadcastReceiver to start your service when it is killed.
Here is a sample code illustrating its implementation:-
#Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("StartkilledService");
sendBroadcast(in);
Log.d("debug", "Service Killed");
}
Then register a receiver in AndroidManifest.xml:-
<receiver android:name=".app.ServiceDestroyReceiver" >
<intent-filter>
<action android:name="StartKilledService" >
</action>
</intent-filter>
</receiver>
Finally,create a BroadcastReceiver,and start your service in the onReceive method:-
#Override
public void onReceive(Context context, Intent intent) {
Log.d("debug", "ServeiceDestroy onReceive...");
Log.d("debug", "action:" + intent.getAction());
Log.d("debug", "Starting Service");
ServiceManager.startService();
}
Hope this helps.
on the service's startCommand method return START_STICKY. generally it tell the OS to start the service when it is killed.
If the situation allows to use 'root' it's usually possible to implement Humpty-Dumpty paradigm.
Your application (1st) installs another application (2nd, taking APK from assets) and runs the service of the 2nd app.
2nd app's service bind to the 1st app service and rebinds when disconnected. The 1st app does the same.
Sure it will not help when all apps are killed by some Free RAM or similar application but when Android kills either of those two, the other one will restart its counterpart.
The only real solution for keeping services alive ist to call Service.startForeground(...) with a provided Notification. This will be the only valid solution, every other one will be very dependent on how Google will change the behaviour of it's system. With every API update, Google could prevent every other hack.
This also keeps the user aware, that your app is performing some background task which will keep the app alive and the user has to stop this. If you provide the user the ability to stop it is part of your application, though.
See the Documentation:
void startForeground (int id, Notification notification)
Make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state. By default services are background, meaning that if the system needs to kill them to reclaim more memory (such as to display a large page in a web browser), they can be killed without too much harm. You can set this flag if killing your service would be disruptive to the user, such as if your service is performing background music playback, so the user would notice if their music stopped playing.
There is a very hacky solution to keep service running even you force stop it. I do not recommend that because it is against user willingness. You can define a broadcast receiver to receive intent with action X. onStartCommand handler of your service, broadcast X (if the service is not started yet). on broadcast receiver upon receipt of X, first start the service, then, sleep for some minutes, and finally re-broadcast X.
I think the only foolproof solution here is to have 2 services in separate processes (android:process="somecustomprocessname" in manifest, in the service entry) that both listen to broadcasts and restart each other, because currently the UI doesn't let users kill multiple processes in one action. You can then set up a pinger thread in each service that checks if the other service is running every 100 milliseconds or so, and if not, attempts to restart it. But this is starting to look more and more like malware...
I'm using a running service to detect whether network is available or not. When it is not available, it calls an activity to start that displays a blank screen with "no network available" on it. When the network is back, it sends a broadcast to finish this activity.
The only problem is that this activity may start at any time (as a popup), even when using other apps. I want it to start (or be visible) only if the network is out and my app is in the foreground. Any help?
One option would be to have your foreground activity register for the broadcast, and then display the relevant notification from within the activity.
Alternatively you could start your service when your foreground activity starts/resumes (i.e, onResume), and stop it when your activity leaves the foreground.
You can use START_STICKY in your service to ensure it stays around until you stop it, like so:
#Override
public int onStartCommand(Intent intent, int flags, int startId){
//On start work here
return START_STICKY;
}
and then stop the service using stopService when your activity leaves the foreground (i.e onPause).
If you need the former behaviour across multiple activities you can register broadcast receivers programmatically:
BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(MY_ACTION.equals(intent.getAction()))
{
//show appropriate dialog
}
}
};
IntentFilter myIntentFilter = new IntentFilter();
myIntentFilter.addAction(MY_ACTION);
registerReceiver(myBroadcastReceiver,myIntentFilter);
You can unregister like so:
unregisterReceiver(myBroadcastReceiver);
You could extend Activity and make your own custom subclass that reuses similar code to register and unregister whilst entering/leaving the foreground. Or you can extract this into utility methods/classes and call from the appropriate places.
I think you need Shared Preference to do this. store one Boolean value on finish you activity (you can use onpause() or onStop()) and for showing popup check the value and do what you want
for understnding to use sharePreference see this and developer.android.com
Try the following:
Intent intent = new Intent(this, YourActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
This worked in the context of my own app already running, I'm not sure if it will start your app if it is not already running in the background
EDIT: Not sure if I understand your question entirely. If you only want this activity to come to the foreground while your app is in the foreground, get rid of the addFlags line, also you can do some boolean stuff to check if your app is in the foreground like so, this way your code won't even run if the app isn't in the foreground.
EDIT: There are a few ways to check if your app is in the foreground, the link I posted above has one such solution, another one is to create a static boolean isForeground variable: in the onResume() methods of your app set isForeground = true and in onPuase() set isForeground = false. This isn't the best practice, using ActivityManager is better, but for purposes of testing this should be ok.
Then have something like the following:
if(isForeground){
//Start your activity
}
This should be quick to write, if this is the behavior you want, I would recommend replacing the isForeground static variable with the test for foreground provided by ActivityManager in the link I posted.
I have created a service which is supposed to receive the android.bluetooth.device.action.ACL_DISCONNECTED/ACL_CONNECTED events.
I am aware that services in android may be restarted/stopped when android decides.
However, I am wondering whether a service is always guaranteed to receive the events it registered for, even it has been killed by android?
I assume this means that android will need to restart a killed service which has registered to listen to events when that event takes place.
Is the above assumption correct ?
Thank you very much for the quick reply.
Let me give some more information, sample of the code follows:
public class my_service extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
IntentFilter filterDisconnected = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(mReceiverDisconnected, filterDisconnected);
...
}
private final BroadcastReceiver mReceiverDisconnected = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
...
}
So with this code the BroadcastReceiver is implemented within the service class.
This code is working fine under normal cirmustances but are you saying that this is not proper and a different class (BroadcastReceiver ) is needed ?
If the above is proper, i am wondering if this service class is stopped for any reason, when the relevant event is raised, the class will be restarted and the BroadcastReceiver will get the event.
Hi all, i have created a service which is supposed to receive the android.bluetooth.device.action.ACL_DISCONNECTED/ACL_CONNECTED events.
That should not be possible. Those are documented as being broadcast actions; if true, then they can only be picked up by a BroadcastReceiver.
However, i am wondering whether a service is always guaranteed to receive the events it registered for, even it has been killed by android ?
Again, services should never "receive" those events directly.
However, if you create a BroadcastReceiver and put it in the manifest with an <intent-filter> for your desired broadcasts, then that BroadcastReceiver is "guaranteed to receive the events it registered for", and that BroadcastReceiver can call startService() to send a command to an IntentService if desired.