Android Service that constantly updates Activity - android

I have built an app for running. It runs an Activity with a timer shown in the user interface, a gps listener that collects coordinates and a lot of other things (the activity does a lot of work).
Now the request of my client is to move all the activity logic in a Service. In this way, when you start a running session, the Service would start and the notification (very simple, just with a static text) would appear. The activity should keep track of the work made in the Service (timer should go on, speed should be shown, ecc...). Tapping on the notification should bring up the activity. If the activity is closed or crashes the Service should keep going on and when you tap on the notification a new Activity should be brought up without the user noticing any difference (the timer should keep showing the right time, the average speed should comprehend the speeds relevated before the activity crash, ecc...).
I know there are a lot of ways to do that.
What I am asking is: what is the best way? Are there examples of such behavior from where to start? What are the common errors I should avoid? Are there best practices to follow?
Thank you

I developed an app with similar service behaviour. It also requires a service which collects data and some activities for showing the data.
For these kind of applications you want to keep the service alive until the user stopps it manualy but it is still possible for android that it kills the service if the device is low on memory.
For the service - activity interaction you need to bind to a service. A good documentation is available here: http://developer.android.com/guide/components/bound-services.html
Be sure to return START_STICKY in the onStartCommand function of the service. This will make sure the intent will be null when the service was restored by the system and tell android that you start and stop your service explicit.
When binding to the service from the activity you need to check if the service is ready (was not restored by the system). This can be done by adding a "ready" field inside the service that is false by default and is set to true if the onStartCommand intent is not null. Therefore you can react properly to a restored service and start the app from the beginning.
To keep the service alive with a high priority you need to call startForeground inside the service. This also requires to show a notification so the users knows a service is running in the background.

Inside service you can use local broadcastmanager.
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
broadcaster = LocalBroadcastManager.getInstance(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);
return START_STICKY;
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo(); //do watever you want to push
handler.postDelayed(this, 1000); // 10 seconds
}
};

Related

Android Service running on separate Process gets killed when I swipe out my App (running in other process)

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.

Stop the Service on Destroy of 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();
}

Android Application kill event capture

I want to perform some operation when my application gets killed.
Which method can be used for this? I am working on Android 5.0.
The key of this question is that:
you must understand your application whether can receive any
additional callbacks when your application being killed in any kinds of situation.
The following answer is answered by Devunwired in this question:
Android app doens't call "onDestroy()" when killed (ICS)
This will help you more to understand this.
Your application will not receive any additional callbacks if the process it terminated by external means (i.e. killed for memory reasons or the user Force Stops the application). You will have to make do with the callbacks you received when you app went into the background for your application cleanup.
finish() is only called by the system when the user presses the BACK button from your Activity, although it is often called directly by applications to leave an Activity and return to the previous one. This is not technically a lifecycle callback.
onDestroy() only gets called on an Activity as a result of a call to finish(), so mainly only when the user hits the BACK button. When the user hits the HOME button, the foreground Activity only goes through onPause() and onStop().
This means that Android doesn't provide much feedback to an Activity to differentiate a user going Home versus moving to another Activity (from your app or any other); the Activity itself simply knows it's no longer in the foreground. An Android application is more a loose collection of Activities than it is a tightly integrated singular concept (like you may be used to on other platforms) so there are no real system callbacks to know when your application as a whole has been brought forward or moved backward.
Ultimately, I would urge you to reconsider your application architecture if it relies on the knowledge of whether ANY Activity in your application is in the foreground, but depending on your needs, there may be other ways more friendly to the framework to accomplish this. One option is to implement a bound Service inside of your application that every Activity binds to while active (i.e. between onStart() and onStop()). What this provides you is the ability to leverage the fact that a bound Service only lives as long as clients are bound to it, so you can monitor the onCreate() and onDestroy() methods of the Service to know when the current foreground task is not part of your application.
You might also find this article written by Dianne Hackborn to be interesting covering in more detail the Android architecture and how Google thinks it ought to be used.
You have to use Service Class for it like -
public class Myservice extends Service { #Nullable #Override public IBinder onBind(Intent intent) { return null; }
#Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(Constants.TAG, "Service Started"); return START_NOT_STICKY; }
#Override public void onDestroy() { super.onDestroy(); Log.d(Constants.TAG, "Service Destroyed"); }
#Override public void onTaskRemoved(Intent rootIntent) { Log.e(Constants.TAG, "END"); //Perfome here want you want to do when app gets kill stopSelf(); } }
In Manifest -
<service android:name="Myservice"
android:stopWithTask="false" />
In Oncreate of your launcher activity or Application Class to start service -
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
You can use your activity's onDestroy() method.

RemoteService - restarts after closing the launching Activity

I'm blocked with this for a few days and can't find the answer on this.
I start a remote service from an Activity. After starting the service, I close the launching Activity.
I close the main Activity from the task manager like this: home_btn long press and the list of opened app appears and then swipe left on the main Activity.
The thing that happens is that my service gets restarted! even thought it is a remote service, that has it's own process, doesn't depend on the launching activity!
All the internal variables are going to be reset and I don't want that.
-I don't want to use useForeground() method because I don't want my service to be visible in Notification
I currently start a Remote Service like this and the service starts(I can see it in the menu Settings->Apps-> tab Running):
btnStartSrv.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
startService(new Intent("com.example.servicerst_tst.RemoteService"));
}
});
android manifest xml looks like this:
<service android:name="com.example.servicerst_tst.RemoteService"
android:process=":serviceTST" >
<intent-filter>
<action android:name="com.example.servicerst_tst.RemoteService" >
</action>
</intent-filter>
</service>
the service class:
public class RemoteService extends Service{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
I'm seeing the service restarting or reseting .. in the DDMS.
When closing main Activity the service disappears from the list in the DDMS and the gets started by itself in about 2 seconds. This can be visible in the service also. If you place some internal variables that get change during the life of the service. They will get reset, like the the service is restarting itself after closing the main Activity.
I just want my service not to reset, restart when I'm closing the main launcher Activity.
If the user closes the launcher Activity, from task manager or by his mistake, I want the service to run in background.
Am I doing something wrong here or missing something from my code to prevent restarting?
Why is reseting the service?
From Android Developers - Services : "if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system".
Declaring your service to run in the foreground has specific requirements: "A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground." and "To request that your service run in the foreground, call startForeground()." I know you said you don't want it to be a foreground service, but you have to live with the parameters Android sets out for you.
Solved problem with restarting service when launching Activity closes!
You should use startForeground() to not have this issue.
So startForeground() solved the restarting problem when closing launching Activity.
I've made also the service, restarting reliable.
Still I have a question..how the services ... like facebook and other big services run in background without any startForeground() implemented.
Also they are not killed by the system and they run in background forever without any startForeground() implementation. they live forever in background. For sure is somehow possible.
Does anyone know how?
How to avoid notification but still implementing the startForeground() method:
This is done By implementing the notification without
.setSmallIcon(R.drawable.ic_launcher)
for other details see
How to correctly handle startForegrounds two notifications

How to start long running background task in android service

Having read most of the available documentation on Android services on the developer site and here in stackoverflow, I'm still confused by several aspects of running a service in a separate task. Hopefully someone can put me on the right track.
Let's say we have trival service framework such as
public class HliService extends Service {
#Override
public void onCreate() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
}
}
and in the manifest, I have
<service android:name=".HliService" android:process=":HLI_Comms"/>
so that the service runs in its own thread.
The intent of the service is to provide a background task that will communicate
to a device using a TCP socket and do some other stuff. At the risk of ignoring battery issues etc, basically I'd like it to run forever.
Something like
// Method that communicates using a TCP socket, and needs to send
// information back to the activity and receive messages from activity
// not shown here.
private void dummytask() {
boolean keepGoing = true;
while (keepGoing) {
// do useful stuff in here
// sets keepGoing false at some point
}
stopSelf();
}
What is the best way to initiate this method/task ?
I have looked at code in the developer site that uses a message handler and a looper, which I only partly understand, but it seems very complicated and perhaps more than I require?
I don't believe I can call this method from either onCreate() or onStartCommand() since then neither would complete when invoked from the system ? Should I start it with a timer or alarm?
I will need to add a message handler to communicate with the the gui activity, but since I'm starting the service in another thread (by virtue of the manifest "process" instruction), do I need to use AIDL instead?
I have also looked at using AysnchTask rather than extending Service, but it seems better suited to running a task and then terminating.
so that the service run in its own thread.
That puts the service in its own process. This is generally something to be avoided, as it consumes extra RAM and CPU (for IPC). You can create a thread just by creating a Thread or any number of other means, most of which have been in Java for a decade or so.
At the risk of ignoring battery issues etc, basically I'd like it to run forever.
It is pretty much impossible for a service to run forever. Users or the OS will get rid of your service eventually.
What is the best way to initiate this method/task ?
Call dummytask() from a background thread.
do I need to use AIDL instead?
No. Your service can broadcast an Intent, or invoke a PendingIntent supplied by the activity, or send a Message via a Messenger supplied by the activity, etc. The best would be to use the LocalBroadcastManager from the Android Support package, but that will not work across process boundaries, forcing you into more expensive communications options.
I think you could use a IntentService which you run by setting up a (regular) alarm (AlarmManager.setRepeating) with a PendingIntent in it. You can notify the UI by broadcasting an Intent from the IntentService and receiving it in your UI through a BroadcastReceiver.

Categories

Resources