How to Stop service when app goes in background - java

I have a multi activity app. In the main activity a service is initiated that plays music. When I navigate through activities the music is still playing ( which is something that I want) but the music is still playing when I click home button and app goes in the background(which is something I don't want).
My first solution was to do 'stopService()' onPause of main activity but this prevented the music from playing in the other activities.
Tried the same in onStop method, same problem occurred.
Q: How can I stop the music(stop the service) from playing when the whole app goes in the background?
My service code:
public class MediaService extends Service {
private MediaPlayer player;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
player = MediaPlayer.create(this, R.raw.music);
player.setLooping(true);
player.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
player.stop();
}
And I start/stop service with:
music_intent = new Intent(this, MediaService.class);
startService(music_intent);
stopService(music_intent);
P.S. Thanks for all the answers but as I said onStop methods stops the music when I change activities which is something that I don't want.

Found this solution in a similar question that uses Application.ActivityLifecycleCallbacks in Application class to check when app goes in Background and then send a Broadcast to the service to stop it.
More in: Stop MediaPlayer service when app goes in Background

According with the Activity lifecicle you should use onStop() to stop your audio from beign played
Remember that onStop()
May never be called, in low memory situations
where the system does not have enough memory to keep your activity's
process running after its onPause() method is called.
So it should solve your problem doing this in this way
#Override
public void onStop() {
super.onStop();
if(player.isPlaying()){
player.stop();
player.release();
}
}

use onStop() or onPause() to stop the service rather than onDestroy();
onStop() - when app goes backgroun(not visible)
onPause() - when any pop-up appears

Here is the actual answer, try this.
For some reason, the service is not stopping when the app goes to background
It stopped long before your stopService() call, as it stopped once onHandleIntent() returned, milliseconds after it was created.
What is not stopping is your Timer, which runs on a background thread and will continue running until you cancel it or your process terminates.
IMHO, this is an inappropriate use of IntentService. If you want to control the lifespan, use a Service, and stop background work in onDestroy().

Related

Android: Run an app when it's definitively closed

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.

Stopping a service when home button is clicked?

I have a service which plays music when the page is loaded, and carries on to all the other pages as it should. It still played when the application was destroyed, so i put a onDestroy method and an onResume method.
#Override
public void onDestroy(){
super.onDestroy();
Intent ServiceMusic = new Intent(this, BackgroundMusic.class);
stopService(ServiceMusic);
}
#Override
public void onResume(){
super.onResume();
Intent ServiceMusic = new Intent(this, BackgroundMusic.class);
startService(ServiceMusic);
}
Now the problem is when the user clicks the home button the service carries on, so I implemented a onPause and it worked fine, just when the user goes to another page the music restarts.
#Override
public void onPause(){
super.onPause();
Intent ServiceMusic = new Intent(this, BackgroundMusic.class);
stopService(ServiceMusic);
}
How can i overcome this so the music carries on playing when going through the application but when the Home Button is clicked i pause the service?
I would remove the code that is in individual activities and use the registerActivityLifecycleCallbacks mechanism in your application subclass. This will allow you to keep the code in one place and be smarter about starting and stopping your service.
Be aware that with these callbacks, you'll be notified that an Activity has stopped before another activity has started, so you will need some kind of delay when you decide to stop your service. You can use a handler with a delayed runnable to account for this issue.
https://developer.android.com/reference/android/app/Application.html#registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks)

Local broadcast in android?

I have two activity activityA and activityB.
activityA is starting a background process and mean while it will also start activityB
background process started by activityA will finish after sometime. Is it possible to notify activityB when process is finish by activityA if activiyB in foreground and activotyA is background.
Yes it is definitely possible and LocalbroadcastMaanager is a good choice here is how you do it.
In the long running process, write this at the end of the process
LocalBroadcastManager.getInstance(context).sendBroadcast(
new Intent("backgroundProcessCallBack"));
And in your activity you should have this (inside oncreate):
LocalBroadcastManager.getInstance(context)
.registerReceiver(mTaskListener, new IntentFilter("backgroundProcessCallBack"));
where mTaskListener is a class level variable (BroadcastReceiver):
private BroadcastReceiver mTaskListener = new BroadcastReceiver() {
#Override
public void onReceive(Context cxt, Intent intent) {
// Do you stuff here. You got the callBack in your activity
}
};
then unregister this receiver in activity's onDestroy() method.
You cannot have two activities running at the same time.
If your background process runs in a Service, you can subsribe to broadcasts in Activity A and in Activity B.
When the work in Service is finished, it sends broadcast - and whatever Activity (A or B) is in foreground - it will receive a Broadcast.
Sample code here: Programmatically register a broadcast receiver

How to keep service running in background when app is closed but stop/disable it when the app is in foreground?

I am having difficulties trying to handle service behaviour in such case.
Basically I have a service running on a separate process that needs to issue httprequests every certain time whenever the app is closed, then write something into preferences or throw a notification.
The logic works fine. The problem I'm having is that I cannot find a way to properly stop/disable that service whenever the app is running, aswell as start it again when the app is being finished or put into background.
I've tried stopping it at #onResume()/#onStart() callbacks of my activities aswell as starting it at #onStop()/#onDestroy() but behaviour doesnt run as expected in any case...
I'll paste here some code snippets of what i've tried so far:
I start/stop services using:
stopService(new Intent(this,NotificationService.class));
startService(new Intent(this, NotificationService.class));
Random activity from my app (all implement this in their callbacks):
#Override
protected void onResume() {
if (Utility.isMyServiceRunning(this)){
Utility.serviceClose(this);
}
super.onResume();
}
#Override
protected void onStop() {
if (!Utility.isMyServiceRunning(this)){
startService(new Intent(this, NotificationService.class));
}
super.onStop();
}
This somehow doesnt work or brings unexpected behaviour since the app moves from many activities, and service ends up being alive when the app is running or stopped when the app is in background/finished.
I've also tried to toggle on/off service logic on service timertask every cicle by asking:
#Override
public void run() {
ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
for(int i = 0; i < procInfos.size(); i++){
if(procInfos.get(i).processName.equals("com.example.myapp")) {
return;
}
}
//service http request logic here
}
But that doesnt work either because process "com.example.myapp" never gets killed (and of course I cannot/want to force finish that), so it never issues any httprequest.
Any Ideas on how to implement this? Any help would be very welcome.
Thanks in advance.
How about binding to your service and then communicating directly with it? Implement a simple on/off boolean, expose a getter/setter on the binding, and then make sure the service checks the boolean before it does any work. That way you can disable it while the app is running without having to actually start/stop the service repeatedly.
http://developer.android.com/guide/components/bound-services.html
Solved with better handling of onStop() onResume() callbacks.

Why does WebView -> onPause only work the first time?

I have a Flash video playing in a WebView. When the user hits the home button, I want to stop the video. I attempt to do this in my Activity:
#Override
protected void onStop() {
Log.i(tag, "onStop");
super.onStop();
this.webView.onPause();
}
I see "onStop" logged out whenever I hit the home button, but the video only stops the first time. I can still hear the audio on all the other times.
The following hack stops the video all the time, but (A) it only stops Flash and not any Javascript timers and (B) it can't shut down any generic Flash video - it can only shut down objects with ID "flashVideo" and with a hook named "stopVideo".
#Override
protected void onStop() {
Log.i(tag, "onStop");
super.onStop();
this.webView.loadUrl("javascript:$('flashVideo').stopVideo();");
}
You could try calling this.webView.destroy() in the onStop() but you would need to reinstantiate the webview and re-add the WebView to the activity programmatically since webView.destroy basically makes it so no other methods may be called on a WebView after destroy.
I had the same issue and i made it work by retaining the state in the BackPressed Method
add the follwing code
mVideoView.stopPlayback();
mCustomViewCallback.onCustomViewHidden();
this might help

Categories

Resources