I created a service that can be started via the startService() method, but it also be bound by the applications. I wish that it can be started only via the startService() method, or in other words, applications should be able to bind to it only when the service is already started.
The service should be started manually and not when an application binds to it.
If the service is running, applications can bind to it.
If the service is not running, when an application tries to bind to it, the service should not start.
However, the default behavior is quite different: in fact, Android starts the service automatically when an application wants to bind to it. I would like to know if is possible to modify this behavior to achieve the above requirement.
If this is not possible, the only alternative would be to stop the service if it has been initiated as a result of a bindService(). Here are the changes to my service class in order to use this way...
// It says if the service was started manually.
private boolean mCorrectlyStarted = false;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOG_TAG, "onStartCommand()");
mCorrectlyStarted = true; // the service is started manually: ok!
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.i(LOG_TAG, String.format("onBind(intent: %s)", intent));
if (mCorrectlyStarted) {
return binder;
}
else {
stopSelf(); // although I make this call, the service is not stopped
return null;
}
}
Why do my changes do not have the desired effect?
It might be good that the service starts when an application invokes the bindService() method, but after verifying that it was not started manually, it should stop itself.
The fact that something, like an Activity, called bindService() means someone is still bound to the service. Calling stopSelf() does not destroy the service since technically the service is still bound by the activity.
It will be destroyed once unbindService is called eventually by the Activity. Binding and starting a service are orthogonal.
I am not sure what you are trying to achieve with this design, maybe provide more info on why you want the service to be started before something can bind to it?
Related
I am trying to understand the Service Life Cycle while working through some Android Open Source Code.
I was looking at a Service implementation which I distilled down to something like the following...
public class MyService extends Service {
public MyService() { super(); }
#Override
public void onCreate() {
super.onCreate();
init();
//==this seems odd to me
//comment in AOSP says startService() is called to make
//sure Service stays around long enough for the async call
//to complete.
startService(new Intent(this, myservice.class()));
doSomeMoreInitAsync();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if(actionableIntent(intent,flags,startId)) {
//do something
//NOTE: the Intent passed to startService() in onCreate()
//above will go around this block of code, doing nothing
//except returning START_STICKY
}
return START_STICKY;
}
public void onDestroy() {
//destroy stuff
}
#Override
public IBinder onBind(final Intent intent) {
return mBinder; //an instance of android.os.Binder derivative
// created when this service was instantiated
}
//other stuff
}
Why would someone want to have onCreate() call startService() on itself like above, doing nothing? The comment in code sheds some light, but it's like assumptions are being made about the Life Cycle that I don't understand. I.e., is it reasonable to expect onCreate() to effectively start its own service?
I know that if a service has already been started then onCreate() will only be called once (unless destroyed and restarted, then a new instance of the service is created and onCreate() is called once on it). My first concern with this example would be that there is an expectation placed upon the underlying Service API implementation that the Service is already in the initialized state before onCreate() is called (else there be an infinite recursion, but there is not).
But isn't onCreate() supposed to be part of the initialization (albeit an optional part for the subclass)?
Is this coding logic a reasonable way of making sure the Service is forced to be an Unbounded Service? Or am I looking at a bad example in the AOSP which may have undefined behavior in the future?
You are correct in that a Service will call onCreate and onStartCommand if it is started via Context.startService. So in this sense, when you return START_STICKY, the Service will continually run until an explicit call to stopService() is called. It will also be destroyed and restarted during this lifecycle.
Another way to create a Service, is by binding to it. As per the docs:
Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand().
So, it's possible for a Service to be created by simply binding to it. However, the lifecycle of a Service indicates that it will remain if it is started or a client is still bound to it. Meaning, that if it was created by a bind command, it will immediately be destroyed as soon as the client unbinds.
So, if a Service starts itself in the onCreate(), it will ensure that it puts itself in the started state regardless of whether it was created by binding or by an explicit call to startService. Since there's no actionable intent, the onStartCommand will just pass straight through. An clients that call startSevice will, presumably, have actionable Intents in which case the Service will perform its duties.
I'm reading the official documentation about Services, but I'm a little bit confused because some things aren't so explicit.
Let's take this snippet:
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startID) {
while(...any condition...) {
//some actions
}
return START_SOMETHING;
}
public IBinder onBind(Intent intent) {
return null;
}
}
My doubts are the followings:
The Android system can destroy a service not bound to the current focused activity and not declared as in foreground. But can the Android system destroy a service even if it is still in the while loop?
When I call stopService() does it wait for the onStartCommand() to get to the return statement?
Where should I insert the stopSelf() call? Just before the return statement?
Can the Android system destroy a service even if it is still in the while loop?
Yes. For some reason, extreme low memory pressure (for example), Android system kills the Service without calling onDestroy() method. Why? Because of Service always runs on UI thread.
When I call stopService() does it wait for the onStartCommand() to get to the return statement?
No. Return statement's action will be executed when Android system kills the Service. But, if you call stopSelf() manually, the return statement's action will be ignored.
Where should I insert the stopSelf() call? Just before the return statement?
Call stopSelf() wherever and whenever you want. For example, if user press a button, call stopSelf() to stop the Service playing a music.
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
}
};
I have an application, where I have put a connection to e certain service in a custom Application class, so that all activities can access it, but I need to close the service once my application is closed.
I want to send the bundled data just one time, not every time a single activity hits onPause/Destroy().
I also figured onTerminate() in the Application class is not always invoked.
Is there a better way to do this?
If you are targeting API level 14 or above you can use the registerActivityLifecycleCallbacks to register a listener and count the launches/stops in onActivityResumed and onActivityStopped. When the counter is 0 then you know there is no more activity in the stack and you can close your service
unfortunately, there is no callback / method to detect when your application process has stopped, or going to be stopped. #Alex suggestion to listen to the Activity lifecycle callbacks can be more tricky then it seems.
but if you want to detect this only for purposes of stopping running Service , then this problem is not relevant, because if your process stooped, then all running services it owns is also stopped anyway!!
if you meant that you want to stop the service when the application is not in foreground (completely different thing..) then the solutions is different:
if you'll always use bindService() instead of startService() within the onResume activity callback, and in the onPause() stop it, then when your app would enter background - the service will be stopped automatically.
another option would be to use the Service callbacks to detect if currently there is bounded activity:
#Override
public IBinder onBind(Intent intent) {
mBoundedToActivity = true;
return mBinder;
}
#Override
public void onRebind(Intent intent) {
mBoundedToActivity = true;
super.onRebind(intent);
}
#Override
public boolean onUnbind(Intent intent) {
mBoundedToActivity = false;
return super.onUnbind(intent);
}
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.