Service that just won't die - android

I finally have my Services running well. They are generating events and Broadcasting using managers. My receiving activity even receives the broadcasts well. I have one final problem though. I have two Services. When I call the onDestroy() only one of them is stopping. THe other one continues to broadcast. It also continues to Listen for changes. THat Service is a LightSensor that monitors for Lux events. In my Receiving Activity when I call
stopService(new Intent(this, LightSensor.class));
The onDestroy actually fires. I know this because I have a Log.d event to show me that it was fired BUT it doesn't die. The SensorListener is suposed to deregister and the Service is suposed to stop, but even after I exit the app, it is receiving from the LightSensor.
Could someone take a look and see why this Service will not die plesae?
LightSensor
#Override
public void onDestroy() {
Log.d(TAG, "OnDestroy");
stopSelf();
mSensorManager.unregisterListener(this, LightSensor);
super.onDestroy();
}

Get rid of stopSelf() in onDestroy(), as it is not needed and may be harmful.
Beyond that, you need to make sure that the listener instance you pass into unregisterListener() is the same listener instance that you used with registerListener().

Related

stopService() doesn't call onDestroy [duplicate]

I have big problems with stopping a service, which plays audio file. I want to stop the current service before I play another file.
Activity:
public void playTrack(View view){
Intent i=new Intent(this,playService.class);
i.setAction("com.c0dehunterstudios.relaxer.PLAY");
if(isPlaying){
stopService(i);
isPlaying=false;
Log.v("ACTIVITY", "Stopping..");
}
startService(i);
isPlaying=true;
}
Service:
#Override
public void OnDestroy(){
Log.v("SERVICE","Service killed");
player.stop();
super.onDestroy();
}
But sadly it doesn't work - actually it doesn't even come down to the "Service killed" inside OnDestroy().
What am I doing wrong?
First, it's onDestroy, not OnDestroy . Second, you must use the #Override annotation for compile-time checking, so your Service code should look somewhat like this:
#Override
public void onDestroy(){
Log.v("SERVICE","Service killed");
player.stop();
super.onDestroy();
}
First, you need to clarify how many types of services in Android. AFAIK, there are:
Foreground service.
Background service.
Bound service.
Intent service.
These services stop in different ways.
Foreground: only stop when you intentionally stop it by calling stopService() in activity or fragment where you start that service or call stopSelf() in its own service. And Please note only these methods trigger service's onDestroy().
Background: stopService() and stopSelf() do in the same way as foreground. Moreover, you should know this service is in the same thread with activity or fragment calling it, so if you destroy activity or fragment, this service will stop also, but without calling onDestroy(). It basically destroys underground. Thus, if you want to catch when this service stops you need to add android:stopWithTask="false" when declaring service in Manifest file like this:
<application>
//....
<service android:name=".services.catchingStopService"
android:stopWithTask="false" />
//....
</application>
And now in your service class, you can override this method which triggers whenever this service stops:
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
// Your job when the service stops.
}
Bound: you need to handle by your self by bindService() and unbindService(), you will find out it's totally the same as starService() and stopService()
Intent: this type of service stops by itself when it finishes its jobs. And you can use ResultReceiver to communicate between service and activity or fragment. It's similar to BroadcastReceiver. You can search for example on Google easily.
Summary: base on your purpose, pick the type of service satisfying you. And they all agree with:
Don't count on onDestroy() to know when service stops because it
sometimes gets called underground; more accurately, onDestroy calls
when stopService() or stopSelf() calls (BoundService works in the
same way, I think, but by a similar method, maybe unBind(), I did not
test yet).
Use attribute android:stopWithTask="false", instead to know when the
service really stops.
All types of service stop when the device shutdown or OS kills it if
device leaks of memory.
You also should have a look at flag return by onStartCommand() to
be able to deal with when services stop like restart service again or
something. Here are some keyword you can search:
START_STICKY
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<actionandroid:name="android.intent.action.QUICKBOOT_POWEROFF" />
I had a similar problem even with onDestroy correctly set up - the answer for which could be useful for people coming to this page. For me, onDestroy was not called immediately during stopService, sometimes for a very long time - leaving the service doing work when it should have stopped.
The answer is that this is expected behaviour - I can guess but don't exactly know why. So my solution in this case was to create a public static method to stop the actions of the service manually, which happens at the time it's called, then stopService() will call onDestroy in it's own good time...
In the case for this example (which is probably long gone, I would probably decide to keep the service running until it's expected to quite the app, but provide ways to change audio file, while the service is still active.
In my case I was printing a log inside the onDestroy and It was not printing the log and I thought onDestroy not calling when I call stopService. but in Android studio many times does not print the log so you can once double check or verify with the debug or toast.

Stop service when app goes to background, using a common Base Activity

I have a Base Activity class to implement common behaviour for all the Activities. All of them extend this BaseActivity.
I'm binding to a service in in the BaseActivity's onStart method and unbinding conditionally in the onStop method. With conditionally, I mean that depending on some option selected by the user, the service should or should not keep running in the background when the app goes to background.
The problem is that sometimes the service keeps running when it shouldn't (this is, when the option for killing it is enabled, and unbindService() is effectively called).
I'm thinking that on every Activity change the service is unbound and bound again. Since bound services are reference counted, maybe my service is bound more times than unbound, so that's why it keeps running at the end, even when I call unbindService().
Additionally, the documentation says something about that:
You should usually pair the binding and unbinding during matching bring-up and tear-down moments of the client's lifecycle. For example:
If you only need to interact with the service while your activity is visible, you should bind during onStart() and unbind during onStop().
If you want your activity to receive responses even while it is stopped in the background, then you can bind during onCreate() and unbind during onDestroy(). Beware that this implies that your activity needs to use the service the entire time it's running (even in the background), so if the service is in another process, then you increase the weight of the process and it becomes more likely that the system will kill it.
Since I'm kind of trying to implement both options, what should be the best approach to implement this?
Finally I changed my approach and decided to use only startService() and communicate with the service using a Local Broadcast Receiver.
I start the service in the onCreate() and stop it in the onDestroy() methods of the Base Activity.
Then, to send a message from the Service to the activity, I use this:
private void sendBroadcastMessage(String msg) {
Log.d(LOG_TAG, "send broadcast message: " + msg);
Intent intent = new Intent(MyService.class.getSimpleName());
// Add data
intent.putExtra("message", msg);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Then, to be notified in the activity:
// handler for the events launched by the service
private BroadcastReceiver mMyServiceReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d(LOG_TAG, "Got message: " + message);
// Do stuff...
}
};
And to register the Receiver in the activity:
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mMonitorReceiver,
new IntentFilter(MyService.class.getSimpleName()));
}

How to stop a Service from running after user stops viewing applications Activities. Android

I have the following code in each of the 5 activities of my app. I wanted to keep the service running that is bound to these five activities. It will play music in the background. However when the user navigates away from the any of these five activities the Service should be killed. Using the code below I am able to get it so that the music plays in the background when navigating between the activities. but the Service keeps running after leaving the application. What is the best way to solve this problem? How about some creative ideas.
I put this Toast message in the onDestroy method of the service so I can tell when the service is stopped.
Toast.makeText(this, "My Service Destroyed", Toast.LENGTH_LONG).show();
I never see any Toast message pop up when I leave the application. The other toast messages do show to indicate that the service has started.
#Override
public void onPause() {
super.onPause();
unbindService(serviceConnection);
}
#Override
public void onResume() {
//After a pause OR at startup
super.onResume();
//add this to the onResume of the activity
// startService(new Intent(this, AudioService.class));
bindService(new Intent(this, AudioService.class),
serviceConnection, Context.BIND_AUTO_CREATE);
}
According to the documentation here:
Multiple clients can bind to the service at once. When a client is done interacting with the service, it calls unbindService() to unbind. Once there are no clients bound to the service, the system destroys the service.
So maybe you're missing some unbind in one of your activities. You can check this by printing a log in the onBind and onUnbind methods of your service.

Service called several times ending itself

I am starting a service with a click on a button :
Intent intent = new Intent(getActivity(), UploadService.class);
getActivity().startService(intent);
My apps makes it possible to launch several services.
I know that the first time, onCreate() is called, then if the services is running, onStartCommand() is called.
onStartCommand returns START_STICKY.
But I'm facing a strange behavior :
On the first click, the Service is called, onCreate() then onStartCommand()... etc.
On the second click, while the Service is still running, onStartCommand()... etc.
But when the first is finished, onDestroy() is called, while the second is still in progress... ?
How to avoid that?
Thanks
If you start the Service that is already running then onDestroy() of Service won't be called and the instance of Service already running will be brought to front but if your Service is finished/stopped explicitly then only its onDestroy() will be called.

When to Register/Unregister Broadcast Receivers created in an activity?

I have a need to create a custom broadcast receiver in the onCreate event of an activity and obviously I need to unRegister the broadcast receiver in the onDestroy event of the activity
For clarity this is a snippet of the code I use
public class AnActivity extends Activity {
private ResponseReceiver receiver;
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP =
"mypackagename.intent.action.MESSAGE_PROCESSED";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new ResponseReceiver();
registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
I have read that onPause/onResume and onStart/onStop events for the activity should also register and unregister the broadcast receiver.
I'm really wanting to understand what is considered to be the best practice for this and why.
You should register and unregister your receivers onStart() and onStop().
The only reason an Activity would register BroadcastReceivers is to use the events in some way on the current activity, to inform the User of an event. If onStop() has been called, then the Activity is no longer in the foreground, and therefore cant update the User.
If you want to receive broadcast events in the background you should consider using a service as indicated here.
Like Konstantin says, onDestroy() is not guaranteed to be called, and you could continue receiving broadcasts for a long time, when the Activity is no longer open.
As onDestroy() is not guaranted to be called you shall use onPause() to deregister. Consider lifecycle of your broadcast receiver: Do you need it to be active, only when your activity is in foreground? Then use onResume() / onPause()
The Android documentation doesn't prescribe a single place to register/unregister broadcast receivers, but it mentions both onStart()/onStop() and onResume()/onPause() as possibilities.
The biggest factor in making this decision is, when does your receiver need to be able to do its job? This will determine when to register and unregister it.
Does the receiver need to do something about the broadcast only when the activity is in focus? If so, you can register/unregister it in onPause()/onReceive(). (You can also use a longer lifetime such as onStart()/onStop(), but then you should check during the receiver's onReceive() whether the activity is in focus.)
Does the receiver need to do something when visible, even if it doesn't have focus (e.g. when a dialog is being shown)? If so, use onStart()/onStop() (or a longer lifetime, but again, the receiver's onReceive() should check whether the activity is visible).
Does the receiver need to know about the broadcast even when the activity isn't visible? For example, does it need to remember that something has happened, so that when the activity becomes visible, it can reflect the resulting state of affairs? Then you need to use onCreate()/onDestroy() to register/unregister. (Note there are other ways to implement this kind of functionality.)
If you register in onStart(), don't also register them in onResume(), because that would be redundant: onResume() is never called without onStart() being called first.
Also keep in mind that it's best to keep onPause() as light as possible:
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop().
It's true that onDestroy() is not guaranteed to be called if the system kills your process in order to save memory. However if the process is killed, the process won't be receiving broadcasts anyway. In that case, is it really necessary to unregister broadcast receivers?
Android can kill your application with omitting onStop() method. The best way to solve that situation is register BroadcastReceiver in onResume() method and unregister in onPause().
You should register and unregister your broadcast in onResume() and onPause() methods.
if you register in onStart() and unregister it in onStop(). that time you will get following issue.
if your device screen is lock that time onStop() is called and if you unlock that time onStart() is never called. thats why you have register and unregister it in onResume() and onPause() methods.

Categories

Resources