我如何让ExoPlayer在我的Activity的onStart()方法中恢复视频?

时间:2017-05-14 00:11:20

标签: android video android-activity exoplayer

我正在使用ExoPlayer从URL播放一些mp4。当用户点击主页按钮或任何导致应用程序从用户视图中删除然后返回我的应用程序(和视频活动)的内容时,我希望视频从中断处继续。我尝试通过在onStop()中保存视频位置,然后在seekTo()中重建播放器并使用onStart()来实现此功能。我检查了onStart()中我当前的exoplayer是否为null,但是这个检查从未通过,所以我认为这就是问题所在。如何编码现在我的视频永远不会恢复。如果我通过按主页按钮离开应用程序onStop()被调用,然后当我回到我的应用程序时会调用onStart(),但视频播放器仍为黑色,从不播放视频。如果我删除空检查,每当我从主活动开始播放视频时,我都会看到两个视频实例,因为它会在onCreate()onStart()中被调用。有没有更好的方法来获得我想要的功能?任何帮助表示赞赏!

public class VideoActivity extends AppCompatActivity {

    private SimpleExoPlayer exoPlayer;
    private SimpleExoPlayerView simpleExoPlayerView;
    private long playerPosition;
    private String mp4Url;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.player_activity);

        // Get the Intent that started this activity and extract the video url
        Intent intent = getIntent();
        mp4Url = intent.getStringExtra(MainActivity.VIDEO_URL);
        // Create an exoplayer instance and start playing video
        buildPlayer(mp4Url);

    }

    private void buildPlayer(String mp4Url) {
        // Create a default TrackSelector
        Handler mainHandler = new Handler();
        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

        // Create the player
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector); // no LoadControl?
        simpleExoPlayerView = new SimpleExoPlayerView(this);
        simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);

        // Set media controller
        simpleExoPlayerView.setUseController(true);
        simpleExoPlayerView.requestFocus();

        // Bind player to the view
        simpleExoPlayerView.setPlayer(exoPlayer);

        // Create Uri from video location
        // TODO: should this be in some network class? Should I be appending APIKEY here?
        Uri mp4Uri = Uri.parse(mp4Url + "?api_key=" + BuildConfig.GIANTBOMB_API_KEY);
        Timber.v("Video url with api key: " + mp4Uri.toString());

        // Create another bandwidth meter for bandwidth during playback (not strictly necessary)
        DefaultBandwidthMeter playbackBandwidthMeter = new DefaultBandwidthMeter();

        // DataSourceFactory to produce DataSource instances through which media data is loaded
        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this,
                Util.getUserAgent(this, "GiantBombForAndroid"),
                playbackBandwidthMeter);

        // Produces Extractor instances for parsing the media data
        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

        ExtractorMediaSource.EventListener eventListener = new ExtractorMediaSource.EventListener() {
            @Override
            public void onLoadError(IOException error) {
                Timber.e("Error loading video from source");
            }
        };

        final MediaSource videoSource = new ExtractorMediaSource(mp4Uri,
                dataSourceFactory,
                extractorsFactory,
                mainHandler,
                eventListener);

        exoPlayer.prepare(videoSource);

        exoPlayer.addListener(new ExoPlayer.EventListener() {
            @Override
            public void onLoadingChanged(boolean isLoading) {
                Timber.v("Listener-onLoadingChanged...");

            }

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                Timber.v("Listener-onPlayerStateChanged...");

            }

            @Override
            public void onTimelineChanged(Timeline timeline, Object manifest) {
                Timber.v("Listener-onTimelineChanged...");

            }

            @Override
            public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
                // TODO: Do I need anything here?
            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
                Timber.v("Listener-onPlayerError...");
                exoPlayer.stop();
                exoPlayer.prepare(videoSource);
                exoPlayer.setPlayWhenReady(true);
            }

            @Override
            public void onPositionDiscontinuity() {
                Timber.v("Listener-onPositionDiscontinuity...");

            }

            @Override
            public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
                // TODO: Do I need anything here?
            }
        });
        exoPlayer.setPlayWhenReady(true);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Timber.v("onStart()...");
        if (exoPlayer == null) {
            Timber.v("No exoplayer instance, recreating...");
            buildPlayer(mp4Url);
            exoPlayer.seekTo(playerPosition);
        }
    }

    @Override
    protected void onStop(){
        super.onStop();
        Timber.v("onStop()...");
        //TODO: pull player creation code into it's own method so it can be called here as well
        playerPosition = exoPlayer.getCurrentPosition();
        exoPlayer.release();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Timber.v("onDestroy()...");
        exoPlayer.release();
    }
}

4 个答案:

答案 0 :(得分:3)

目前你正在调用onStop()中的释放,这将取消播放器的所有重要部分,但不会取消exoPlayer字段(并销毁任何你没有跟踪自己的状态)。

有几种不同的方法。但无论你做什么,你都可能想要自己跟踪一些状态。下面我将它们用作字段,但它们也可以放在onSavedInstanceState()中。在onStop()中,我们将两条信息保存起来,然后在onStart()中删除它们。 1)暂停时我们的球员所处的最后位置和2)我们是否应该在恢复时进行比赛。您可能会将seekTo来电移出if == null区域,因为您可能始终希望从中断的位置恢复。

@Override
public void onStart() {
    // ...

    if (exoPlayer == null) {
        // init player
    }

    // Seek to the last position of the player.
    exoPlayer.seekTo(mLastPosition);

    // Put the player into the last state we were in.
    exoPlayer.setPlayWhenReady(mPlayVideoWhenForegrounded);

    // ...
}

@Override
public void onStop() {
    // ...

    // Store off if we were playing so we know if we should start when we're foregrounded again.
    mPlayVideoWhenForegrounded = exoPlayer.getPlayWhenReady();

    // Store off the last position our player was in before we paused it.
    mLastPosition = exoPlayer.getCurrentPosition();

    // Pause the player
    exoPlayer.setPlayWhenReady(false);

    // ...
}

现在,我在您的代码示例中看到的另一个问题是,exoPlayer.release()不会使字段exoPlayer无效。因此,您可以在exoPlayer = null之后添加行exoPlayer.release(),这有助于解决您的多个exoPlayers问题。您也可以将release()电话移至onDestroy(),但前提是您知道正在重新正确地重新安排所有内容。

答案 1 :(得分:1)

无需重新启动播放器。下面的代码就足够了:

 @Override
 protected void onPause() {
     super.onPause();
     if (player!=null) {
         player.stop();
          mLastPosition = player.getCurrentPosition();
     }
 }

 @Override
 protected void onResume() {
     super.onResume();
     //initiatePlayer();
     if(mLastPosition!=0 && player!=null){
         player.seekTo(mLastPosition);
     }
 }

答案 2 :(得分:0)

尝试以下

  1. 在onPause中获取玩家位置。
  2. 在onResume中再次启动播放器并将搜索设置为播放器的最后一个位置

     private void initiatePlayer() {
    
            try {
    
                exoPlayer = ExoPlayerFactory.newSimpleInstance(this);
    
                DataSource.Factory dataSourceFactory =
                        new DefaultDataSourceFactory(this, Util.getUserAgent(this, this.getResources().getString(R.string.app_name)));
                DefaultExtractorsFactory extractorsFactory =
                        new DefaultExtractorsFactory()
                                .setMp4ExtractorFlags(Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS);
    
                ProgressiveMediaSource progressiveMediaSource =
                        new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
                                .createMediaSource(videoUri);
                // playerView = new PlayerView(this);
    
    
                playerView.setPlayer(exoPlayer);
                exoPlayer.prepare(progressiveMediaSource);
                exoPlayer.setPlayWhenReady(true);
    
                PlayerControlView controlView = playerView.findViewById(R.id.exo_controller);
                mFullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
                ImageView volumeControl = controlView.findViewById(R.id.exo_volume);
                mFullScreenIcon.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if(ORIENTATION ==Configuration.ORIENTATION_LANDSCAPE){
                            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                        }else {
                            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                        }
    
                        Timer mRestoreOrientation = new Timer();
                        mRestoreOrientation.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                            }
                        }, 2000);
                    }
                });
    
                volumeControl.setOnClickListener(view -> {
                    float currentvolume = exoPlayer.getVolume();
                    if (currentvolume > 0f) {
                        previousVolume = currentvolume;
                        exoPlayer.setVolume(0f);
                        volumeControl.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_volume_off_white_24dp));
                    } else {
                        exoPlayer.setVolume(previousVolume);
                        volumeControl.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_volume_up_white_24dp));
                    }
                });
    
            } catch (Exception e) {
                e.printStackTrace();
                Log.d("MainExcep", e.getMessage());
            }
        }
    
     @Override
        protected void onPause() {
            super.onPause();
            if (exoPlayer!=null) {
                exoPlayer.stop();
                mLastPosition = exoPlayer.getCurrentPosition();
            }
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
            initiatePlayer();
            if(mLastPosition!=0){
                exoPlayer.seekTo(mLastPosition);
            }
        }
    

答案 3 :(得分:0)

就我而言,如果我最小化或尝试从此播放器视频应用程序移至另一个应用程序。视频播放器应用程序始终从0开始播放。我尝试并成功地将视频播放器应用程序最小化或移动到另一个应用程序时从最近的当前位置播放视频。

转到

private void buildPlayer(String mp4Url)

添加

   player.seekTo(playbackPosition);

然后

@Override
public void onResume() {
    super.onResume();
    if(playbackPosition!=0 && player!=null){
        player.seekTo(playbackPosition);
        initializePlayer();
    }
}

@Override
public void onPause() {
    super.onPause();
    player.stop();
    if(player != null && player.getPlayWhenReady()) {
        player.stop();
        playbackPosition = player.getCurrentPosition();
        player.setPlayWhenReady(true);
    }

}

@Override
public void onStop() {
    super.onStop();
   player.setPlayWhenReady(false);
   player.stop();
   player.seekTo(0);
}

您可以尝试删除

    exoPlayer.setPlayWhenReady(true);

来自

private void buildPlayer(String mp4Url)