26

EDIT - FOUND A EASY 5-10 LINE SOLUTION!!! See MY OWN ANSWER BELOW!!! YAY!!!!!!!!!

I've searched for 5 hours, dozens of SO posts, no answers, and this seems like the most simple obvious freaking thing!!!

EDIT- btw, this is NOT a music player app, just an app to view pics and text, opens multiple activities like menu and about, view diff types of pictures etc. I just want to play some simple background music while looking thru the pics and text, why is that so difficult?

another EDIT - it seems the main question really is: "WHY DOES PRESSING THE HOME BUTTON NOT CALL onPause or onStop ???" -so I can know when to stop the media player? and how do the games I download on the market accomplish this???

home activity starts

then

media player starts:

player = MediaPlayer.create(this, R.raw.idil);
player.setLooping(true);
player.setVolume(100,100);
player.start();

Player declared outside of onCreate

MediaPlayer player;

When other activities are opened, the background music continues uninterrupted, which is GOOD, that is what I want.

Now, when I am done with my very simple app (that just shows some pics and texts in diff activities), I either click BACK multiple times to get to the home/original activity, and then one more time to "exit", OR, I simply press home to "exit" because I'm DONE with this app and I do not need to hear that music anymore.


OPTION 1

Call player.stop(); in an onPause override, this is not what I want because background music stops when I leave the home activity for other activities like 'menu' and 'about', I also do not what to use pause and resume when opening new activities because I do not want the pretty background music to 'skip' or be interrupted.


OPTION 2

@Override
    protected void onPause() {
        super.onPause();
        if (this.isFinishing()){
            player.stop();
        }
    }

This is better because background music does not stop between activities, and when I press BACK from my home activity, the music stops, and I can continue to enjoy my android fun phone in peace and quiet, but the problem is, when pressing the HOME button to "exit" my app, that pesky background music keeps playing.


ODDLY

@Override
protected void onStop() {
        super.onStop();
        if (this.isFinishing()){
            player.stop();
        }
    }

Does the same as onPause (and I do understand the actual differences)

EDIT- ALSO it doesn't seem to matter if player.stop(); is above or below super.onStop(); but it affecting something i cant see, either way, still no SOLUTION :(

ooooo

ooooo

EDIT- ANOTHER OPTION- BUT DOES NOT WORK

public void onUserLeaveHint() {
    player.stop();
    super.onUserLeaveHint();
}

this stops the music when i press HOME but it also stops it when i start new activities :(

EDIT - A VERY COMMON WORK AROUND IVE SEEN MULTIPLE PLACES, but seems to ridiculous to have to do:

essentialy keep count of the number of activities that have been opened and closed (onResume and onPause would prob be best, but that points irrelevant) and when that count reaches 0, stop the background music. YES that is pretty simple, but why do I have to programmatically do this, actually the BIGGEST QUESTION FOR THIS POST IS:

WHY DOES PRESSING THE HOME BUTTON NOT CALL onPause or onStop ???

To put it in onDestroy is not an option because onDestroy is only called when the system is low on memory, or you force close your app, and that is well documented.

Overriding the HOME button also is no option as I have read it's "not possible" and I have read it's "extremely frowned upon", either way I'm avoiding that.

I don't see the need to create SERVICE, and even if I did, when would I stop the service, it seems I would have the same problem

NOW HERE IS THE THING that completely blows my mind, every game and every app I have downloaded from the android market has very beautiful background music, and when I press BACK or HOME because I am done playing that lovely game the music stops, not keeping playing in the background.

I am very frustrated, and I feel it's because I feel like I am missing something very simple, because this is one of the most basic lifecycle issues with any app.

I spent a month reading every page of developer.android.com including the Dev Guide, the tutorials, sample projects, and researching the Reference section, as well as google-ing this topic for 5 hours.

I also don't understand why the 6 or 7 SO threads with the exact same issue, have not been answered, every downloadable app on the market stops playing its music (unless its a background music player) when you press HOME or BACK or whatever to "exit" the app to go do something else on your phone.

What am I missing?

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
Mike
  • 489
  • 1
  • 4
  • 11

9 Answers9

22

I'm very happy today, and still have hair :) I've tested this and it works!!!

First, add this to your Manifest:

<uses-permission android:name="android.permission.GET_TASKS"/>

Second, add this to your 'Home/Main' Activity/Class:

  @Override
  protected void onPause() {
    if (this.isFinishing()){ //basically BACK was pressed from this activity
      player.stop();
      Toast.makeText(xYourClassNamex.this, "YOU PRESSED BACK FROM YOUR 'HOME/MAIN' ACTIVITY", Toast.LENGTH_SHORT).show();
    }
    Context context = getApplicationContext();
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    if (!taskInfo.isEmpty()) {
      ComponentName topActivity = taskInfo.get(0).topActivity; 
      if (!topActivity.getPackageName().equals(context.getPackageName())) {
        player.stop();
        Toast.makeText(xYourClassNamex.this, "YOU LEFT YOUR APP", Toast.LENGTH_SHORT).show();
      }
      else {
        Toast.makeText(xYourClassNamex.this, "YOU SWITCHED ACTIVITIES WITHIN YOUR APP", Toast.LENGTH_SHORT).show();
      }
    }
    super.onPause();
  }

And obviously replace xYourClassNamex with, well, Your Class Name :)

Now obviously you do not need the "Toasts" but it will tell you what is going on. The very intersting thind is when you press BACK from your 'Home/Main' activity, you obviously get 2 Toasts, "YOU PRESSED BACK FROM YOUR 'HOME/MAIN' ACTIVITY", and the 2nd Toast is "YOU SWITCHED ACTIVITIES WITHIN YOUR APP". I believe I know why this happens, but it doesn;t matter because I call "player.stop();" from the 2 scenarios that mean my app is no longer being 'used'. Obviously do more work than "player.stop();" if you need to :) And also obvious you dont need the "else" for "YOU SWITCHED ACTIVITIES WITHIN YOUR APP", because there is no reason to "stop/pause" the background music, which is what i needed, but if you DO need to do something when new activities are started, well here you go :)

Hope this helps anyone looking to know when the user "leaves/exits/is done with" the app :)

THANKS FOR ALL OF THE COMMENTS POSTS AND HELP EVERYONE!!! YAY!

EDIT-

This part has to be in EVERY activity's onPause:

Context context = getApplicationContext();
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        if (!taskInfo.isEmpty()) {
          ComponentName topActivity = taskInfo.get(0).topActivity; 
          if (!topActivity.getPackageName().equals(context.getPackageName())) {
            player.stop();
            Toast.makeText(xYourClassNamex.this, "YOU LEFT YOUR APP", Toast.LENGTH_SHORT).show();
          }
        }

so you'll know if the user left your app from ANY of the activities. this is good to know :)

Mike
  • 489
  • 1
  • 4
  • 11
2

The way the media player works is that its runs as a service and then is stopped MANUALLY when the user stops it in the application itself.

Example:

When the media player is playing a song and the user hits home, obviously the user still wants to listen to the song as its a background task. After the user is done listening then the user manually stops it by going into the application and stopping (Aka stopping the service that is playing the song) it or if the playlist is done, then stop. Simple.

This is the expected behavior. And it is exactly how the Music App works.

UPDATE

@Override
    protected void onPause() {
        super.onPause();
        if (this.isFinishing()){
            player.stop();
        }
    }

Needs to be changed to

@Override
    protected void onPause() {
        super.onPause();
        if (mediaPlayer != null){
            mediaPlayser.stop();
            if (isFinishing()){
            mediaPlayer.stop();
            mediaPlayer.release();
            }
        }
    }

An explanation:

The reason we are checking for the object not being null is obvious. However; when we enter the pause, we want to ensure that the mediaplayer is stopping. BUT if we are leaving and the song is almost done, then stop it and release it.

UPDATE 2

Check the link here:

https://stackoverflow.com/a/6704844/529691

This can be used to detect if your application has been moved out of the current tip of the application stack.

Community
  • 1
  • 1
JoxTraex
  • 13,423
  • 6
  • 32
  • 45
  • that makes sense, so what do i use to play simple background music in my app that the user obviously DOESNT want to hear when they are not using my app, is it something other than MediaPlayer() ??? – Mike Feb 05 '12 at 11:18
  • This is common specific to a game. I forget what they use, let me look up one of my books. – JoxTraex Feb 05 '12 at 11:20
  • One thing that you can do is bind a singleton service that all parts of your application will reference. This will allow you to better control it since all parts of your code are using the same object. This would require binding a service in a class that extends Application. – JoxTraex Feb 05 '12 at 11:33
  • your update will stop the bg music everytime a new activity is opened. and my app has nothing to do with music, its took look at photos and text quotes, its just plays an mp3 in the background to listen to while you are browsing. the music just needs to stop when the user decides to stop using my app, either by returning to the home screen, or opening another app – Mike Feb 05 '12 at 11:42
  • Ah, your OP should have stated that. I thought it **WAS** a music app. Check up updated post. – JoxTraex Feb 05 '12 at 11:45
  • btw, my OP mentioned simple app to look at pics i thought but either way i put an edit at the top to make it much more clear, still no simple solution tho :( – Mike Feb 05 '12 at 12:11
  • If an application has activity more than one, while activity changing the music must be paused short of time. That is terrible I think. – lulumeya Feb 05 '12 at 13:11
  • I tried that, but it does nothing! I put this code in my BaseActivity, which was extended by all other activities – Ruchir Baronia Nov 11 '15 at 21:39
  • What is `isFinishing()`? – Ruchir Baronia Dec 17 '15 at 04:07
  • @RuchirBaronia https://developer.android.com/reference/android/app/Activity.html#isFinishing() – JoxTraex May 20 '16 at 03:24
1

Why don't you just make a button to stop the music its so much easier and you don't have to force close everytime

Button exit =(Button) findViewById(R.id.exit);

    exit.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v)
            {
                // TODO: Implement this method

                startActivity(new Intent("com.justme.worldexplorer.EXIT"));             
                finish();
                Music I'd.stop();}});}

There you go and so the key hardware button back dosent leave if you press by accident

public boolean onKeyDown(int KeyCode,KeyEvent event){


    return false;
}

And that's it set it up in the manifest and run if any problems let me know

1

I faced same problem. I will tell you my solution. I overrided onStop, onStart each activity and counted my started activity with some delay and count reaches zero, I paused music.

lulumeya
  • 1,619
  • 11
  • 14
  • This is not a good implementation, the implementation that should be followed is the Music's app example. – JoxTraex Feb 05 '12 at 10:57
  • lulumeya, it seems this is a common issue, and yet no solution, and overriding MANY MANY onResume, onStop, onPause methods in MANY MANY activities seems like a terrible way to have to do it (im saying your answer is terrible, because it works, and im facing the same issue) but really android developers have to override dozens of methods just have some nice bg music while your fooling with your app??? – Mike Feb 05 '12 at 11:21
  • if you facing same issue that means something is wroing while implementing because my app is working great, my app is game and all of activity has bg music. Anyway, if there's something good solution working, I want to know too. – lulumeya Feb 05 '12 at 13:05
  • @JoxTraex In your sample, case of activities changing in your app, music must be pausing short of time, and I solved it with this work, also I don't know better solution yet. And I think saying others answer as a terrible one is not a good manner. – lulumeya Feb 05 '12 at 13:10
1

how is it about un/register as a listener @ the service in onStart() and onStop() method of your activities and every time a listener is (un)registered your service checks if it's got some listeners left in its ArrayList<Listener>. if the listOfListeners.size() is 0 then your service calls its stopSelf() method and kills itself.

at least that's how I would implement this...

so, the things you would need are:

  • 2 Interfaces (Observer, Observable)

  • implement Observer in Activity, Observable in Service

  • ArrayList<Observer> in Service

  • registerObserver(Observer o) and unregisterObserver(Observer o) in Service

but that's just my point of view...

herom
  • 2,532
  • 29
  • 41
  • That is one way to do it, a little uncessary since you'd have a bunch of basically garbage in a list. Not good. – JoxTraex Feb 05 '12 at 11:54
  • what do you mean by "bunch of basically garbage in a list"? does it affect the performance of your app if you use `ArrayList` or `List` @JoxTraex ? How would you implement the `Observer pattern` in Android or is it an absolutely *nogo* in Android and one should use some other solutions to achieve the same? – herom Feb 05 '12 at 11:58
  • herom, this seems to be a very common work around, but seems crazily unnecessary, and Jox is right, but after 2 more hours of research, it seems most people use this solution :( – Mike Feb 05 '12 at 12:00
  • perhaps another solution would be to override the `dispatchKeyEvent(KeyEvent event)` in any of your Activities and call the `stopService(Intent intent)` if `event.getKeyCode()` equals `KeyEvent.KEYCODE_HOME` like in the example in this thread: http://stackoverflow.com/questions/5907102/home-button-listener – herom Feb 05 '12 at 12:13
  • my post specifically says not overriding the home key, BUT i'll look into it – Mike Feb 05 '12 at 12:18
  • you can't get the home button, it is **NEVER** delivered to apps. – JoxTraex Feb 05 '12 at 12:46
  • thanks a lot @JoxTraex, I didn't noticed this until now (I never had to catch the HOME button in any of my apps)... – herom Feb 05 '12 at 12:51
0

In each activity, bind to the service in onStart() and unbind from the service in onStop(). When start the service, only bind to it and do not call startService(...).

By calling startService() the service will continue to run until stopService() is called, regardless of the number of activities bound to it. If you don't call start service, then the service will automatically stop once all activities have unbound from it.

So by binding and unbinding on each activity's onStart() and onStop() methods, you will find that the service (music) will continue until you leave your application with the home button, back key, screen timeout, etc.

TomEverin
  • 415
  • 1
  • 5
  • 12
  • You never know when Android will finally kill the last activity.. So maybe you will press home button and continue hearing the music... – Vito Valov Jul 25 '15 at 19:20
0

For those still looking for a solution in lollipop or just without using permission thing, I came up with another solution as last resource. We can measure the time user has been afk. If it was more than X ms, then you can consider he left the application and stop the music.

So I'm using Application child where I store the time afk and BaseActivity to override onPause and onResume of all my activities.

Vito Valov
  • 1,765
  • 1
  • 19
  • 37
0

I have encountered the same problem with my development proccess.

I solved this by using onPause and onResume and with pause() and start() methods in the player which I saved on my main container, calling fragments instead of activities.

I kept a flag on a singleton in order to know when the music was turned off by the user.

Another problem I found is that my app (idk if it's part of the android build or not) was running the onResume method right before he got the player back on, so I ran a while loop in order to receive the player not as a null pointer, and it works because it runs on a different thread, therefore enabling the app to run the onResume without crashing and the music alongside it.

I find it better (smaller code to write) and non-permission invasive ;).

0
private static HashMap<String, Boolean> focus = new HashMap<String, Boolean>();

public static void check(Context context, boolean hasFocus)
{
    handler.removeMessages(0);
    focus.put(((Activity)context).getLocalClassName(), hasFocus);
    handler.sendEmptyMessageDelayed(0, 500);
}

public static void check(String classname, boolean hasFocus)
{
    handler.removeMessages(0);
    focus.put(classname, hasFocus);
    handler.sendEmptyMessageDelayed(0, 500);
}

private static Handler handler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        Iterator<Boolean> it = focus.values().iterator();
        while(it.hasNext())
        {
            if(it.next())
                return;
        }
        pause();
        super.handleMessage(msg);
    }
};

this is an manager class methods.

each activity implementing like after code

@Override
public void onWindowFocusChanged(boolean hasFocus)
{
    MusicManager.check(this, hasFocus);
    super.onWindowFocusChanged(hasFocus);
}

I'm using this code with my game which is published and working great.

What part of this code is terrible? and where's better solution? I want to know if exist.

Mike, you answered to me my answer is terrible and not working, What's wrong with this?

lulumeya
  • 1,619
  • 11
  • 14
  • 1
    lulumeya, it deff wasnt an insult or anything, my eact quote is "terrible way to have to do it (im saying your answer is terrible, because it works, and im facing the same issue)" - oh wow, i just saw my typo, it should say "im saying your answer is NOT terrible", my apologies. my point was your answer, although i have not reied or tested it, im sure works perfectly fine. but ur using 30 lines of code, accessing multiple methods, using handlers, loops, when it should be one simple line -- "if appClosing/Exiting {do this/stop music}... why is that not already in android?!?!?!?! – Mike Feb 06 '12 at 03:56
  • or maybe more specificall: if USER leaves app via HOME or BACK or ANSWERCALL or ANYTHING { do some work, save, stop music, pause game, atc... } – Mike Feb 06 '12 at 03:59