我正在使用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();
}
}
答案 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)
尝试以下
在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)