Как мне заставить ExoPlayer возобновить воспроизведение видео в методе onStart () моей Activity?

Я использую ExoPlayer для воспроизведения некоторых файлов mp4 по URL-адресу. Когда пользователь нажимает кнопку «Домой» или что-либо, что приводит к удалению приложения из поля зрения пользователя, а затем возвращается в мое приложение (и видео-активность), я хочу, чтобы видео возобновлялось с того места, где оно было остановлено. Я попытался реализовать это, сохранив позицию видео в onStop(), а затем перестроив проигрыватель и используя seekTo() в onStart(). У меня есть проверка, чтобы убедиться, что мой текущий exoplayer равен нулю в onStart(), однако эта проверка никогда не проходит, поэтому я думаю, что здесь проблема. Как это сейчас кодируется, мое видео больше не возобновляется. Если я выхожу из приложения, нажимая кнопку «Домой», вызывается 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();
    }
}

person intA    schedule 14.05.2017    source источник


Ответы (4)


В настоящее время вы вызываете release в 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(), но только если знаете, что восстанавливаете все правильно.

person Kyle Venn    schedule 23.05.2017

Повторная установка плеера не требуется. Достаточно следующего кода:

 @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);
     }
 }
person ivo_stefanoff    schedule 20.02.2020

Попробуйте следующее

  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);
            }
        }
    
person jennifer sashi    schedule 07.11.2019

В моем случае, если я сворачиваю или пытаюсь перейти из этого видео приложения проигрывателя в другое приложение. Приложение видеоплеера всегда начинает воспроизведение с 0. Я пытался и успешно, приложение видеоплеера воспроизводило видео с последней текущей позиции, когда вы минимизируете или переходите в другое приложение, и это все.

go to

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)
person Harun Arrosyid    schedule 24.04.2020