8

I have one activity with 2 fragments (not a ViewPager) & want to use ExoPlayer2 in one of the fragments to play content. The initial fragment shows a list of content & when clicked the second fragment is shown to play the selected content. However when I click back to the initial fragment I can still hear the content playing; it's as though the second fragment is still open. I'm (trying to) release the player this way:

@Override
public void onStop() {
    super.onStop();
    releasePlayer();
}

public void releasePlayer() {

    if (player != null) {
        player.setPlayWhenReady(true);
        player.stop();
        player.release();
        player = null;
        trackSelector = null;
        simpleExoPlayerView.setPlayer(null);
        simpleExoPlayerView = null;
        System.out.println("releasePlayer");
    }
}

I read this but it didn't provide much of a solution. Also, read several posts where ExoPlayer is used in ViewPager fragments but not exactly sure how those examples released the player. Followed the releasePlayer() method from the demo app found here but no luck. Called releasePlayer() from onPause(), onDetach(), onDestroyView() but it made no difference.

Here's some logging set up after the listener is added to the player but don't see anything to explain why it's not releasing...

07-05 19:01:07.216 2529-2643/? V/RenderScript: 0xe0494000 Launching thread(s), CPUs 4
07-05 19:01:11.871 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:11.876 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onTimelineChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onLoadingChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onTimelineChanged...
07-05 19:01:11.904 3064-3064/? V/MediaCodecInfo: Listener-onLoadingChanged...
07-05 19:01:12.467 3064-3064/? V/MediaCodecInfo: Listener-onTimelineChanged...
07-05 19:01:12.468 3064-3064/? V/MediaCodecInfo: Listener-onTimelineChanged...
07-05 19:01:12.515 3064-3099/? V/SoftFFmpegVideo: got OMX_IndexParamPortDefinition, width: 320, height: 180
07-05 19:01:12.708 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:12.708 3064-3064/? V/MediaCodecInfo: Listener-onPlayerStateChanged...
07-05 19:01:13.380 3064-3064/? V/MediaCodecInfo: Listener-onLoadingChanged...
07-05 19:01:13.655 3064-3064/? V/MediaCodecInfo: Listener-onLoadingChanged...
07-05 19:01:18.528 3064-3099/? V/SoftFFmpegVideo: ~SoftFFmpegVideo

Tried the button click but it failed

fragmentExoBinding.button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            System.out.println("button click");
            releasePlayer();
        }
    });

It was crashing everytime I shut it down (using back press, home or recent) b/c there's no longer a player. Updated the releasePlayer() method with if (player != null) but can still hear the content playing even after button click.

JC23
  • 956
  • 3
  • 11
  • 26
  • What happens if you call `releasePlayer();` and *then* `super.onStop();` ? – Martin Marconcini Jul 05 '17 at 20:56
  • Thanks @Martin but made no difference, can still hear the audio even though I'm back on the initial fragment – JC23 Jul 05 '17 at 22:17
  • No other log? I haven’t used exoplayer in a while, but I recall it had a state machine and what not and most things were asynchronous (due to the fact that it’s mostly native c++ code wrapped in java). – Martin Marconcini Jul 05 '17 at 22:37
  • @Martin see my edit – JC23 Jul 05 '17 at 23:21
  • nothing relevant… my only suggestion is to “start over” with a blank app, and try to make the sample work. If a super simple 2 fragment sample works, then you can take it from there. Are you “clicking” the back button? Did you override back? Are you doing a popBackstack? (just trying to think who may be keeping a hard reference…) btw, I think you will want to do `if (player != null)` in onStop too, but that’s irrelevant. – Martin Marconcini Jul 06 '17 at 00:13
  • Thanks for all your feedback @Martin. For now I'll keep at it, the releasePlayer() method from the demo app works fine but the player is in an activity rather than a fragment. Guess I'll go that route if unable to solve it. Just clicking the back button, no override or anything out of the ordinary. – JC23 Jul 06 '17 at 14:34

3 Answers3

2

I am using ExoPlayer inside the Activity and I am using a two-step process. onPause I am stopping the playback:

private SimpleExoPlayer player;     
@Override
protected void onPause() {
    super.onPause();

    // Pause video if it's playing
    if (isVideoPlaying()) {
        if (player != null)
            player.setPlayWhenReady(false);
    }
}

And onDestroy I release the player

@Override
protected void onDestroy() {
    releasePlayer();
    super.onDestroy();
}

private void releasePlayer() {
        if (player != null) {
            player.stop();
            player.release();
            player = null;
        }
    }
Kirk_hehe
  • 269
  • 4
  • 15
  • Thanks @Kirk_hehe. I've previously had success using an activity but trying to update the app from multiple activities to a single activity with multiple fragments. – JC23 Jul 06 '17 at 14:49
0

I have a theory, but I’m not sure. To avoid writing over 9000 comments, I’ll post it is an answer.

  1. Does the player stop (and gets released) if you add a <Button> to your Layout and onClick() call releasePlayer(); ?

  2. If the above works, then override your activity’s onBackPressed() and before calling super.onBackPressed(), get your fragment’s instance and call the releasePlayer(). You can have your fragment implement some interface if you wanna please the Java people and pretend one day you will unit test that… or you can make the method public and cast it to your fragment and spend 5 seconds instead of wasting 5 minutes and 16kb of memory :)

Anyway, interface example:

public interface BackHandlerListener {
    void onBackPressed();
}

Then have your fragment…

class MyFragment extends Fragment implements BackHandlerListener {
    @Override
    public void onBackPressed() {
        releasePlayer();
    }
}

and your activity…

    @Override
    public void onBackPressed() {
        // get your fragment’s instance
        Fragment fragment =
         getSupportFragmentManager() 
            .findFragmentById(R.id.your_fragment_container);

        if (fragment instanceof BackHandlerListener) {
            ((BackHandlerListener) fragment).onBackPressed();
        }

        super.onBackPressed();
    }

You get the drill.

  1. If #1 didn’t work, then there’s something weird going on with your player, that refuses to stop, but seems to be somewhat unrelated to the Fragment’s lifecycle. (*)

(*) Unless the problem is that the media player is dying when the fragment gets stopped and the reference gets leaked (because it’s native code). If this is the case, I’m afraid I’d have to read more about how ExoPlayer2 works these days (last time I used media player, ExoPlayer1 was a “beta” thing that promised a better experience, but didn’t work well with all devices). In those days, I had to use an Android Service to keep the MediaPlayer around and playing and send broadcast intents to my service to command it. ¯_(ツ)_/¯

Martin Marconcini
  • 23,346
  • 18
  • 98
  • 135
  • Honestly, at this point I’d have to build an app with ExoPlayer myself to test it. If you have a working demo with fragments, hit me up and I’ll take a look (*) at some point when work allows :) – Martin Marconcini Jul 10 '17 at 18:44
0

Your question suggests that onStop() of your Fragment is not called.

Are you not using the same Fragment object for both screens or create another unnecessary instance somewhere else?

Maciej Beimcik
  • 2,672
  • 1
  • 18
  • 26