问题描述
基本上,我们要构建一个分页的水平滚动视图,每页上只有一个视频播放器;更改页面焦点后,视频应自动播放并自动暂停/停止.因此,我决定使用ViewPager来显示视频片段.每个片段都有自己的SurfaceView和MediaPlayer用于视频播放.目标是在加载初始页面以及用户滑动以选择新页面时自动播放视频.
Basically, we want to build a paged horizontal scroll view with one video player on each page; Video should auto-play and auto-pause/stop when page focus is changed. So I decided to use a ViewPager to show video Fragments. Each fragment has its own SurfaceView and MediaPlayer for video playing. The goal is to auto-play video when initial page loads and when user swipes to select a new page.
我面临一些问题:
- 加载初始页面后,无法从ViewPager获得回调.我尝试实现ViewPager.OnPageChangeListener以便暂停上一页的视频并尝试在新选择的页面上播放视频.但是,当加载索引为0的页面作为初始页面时,不会调用"onPageSelected".有人知道还有另一种方法来回呼初始页面加载吗?
这是我对ViewPager.OnPageChangeListener的实现
Here's my implementation of ViewPager.OnPageChangeListener
@Override
protected void onCreate(Bundle savedInstanceState) {
…
mViewPager.setAdapter(mVideoFragmentPagerAdapter);
mViewPager.setOnPageChangeListener(this);
mViewPager.setCurrentItem(mSelectedClipIndex);
…
}
....
/* ViewPager.OnPageChangeListener */
private int mCurrentPagerIndex = 0;
@Override
public void onPageScrolled(int i, float v, int i2) {
}
@Override
public void onPageSelected(int i) {
if (mCurrentPagerIndex != i) {
VideoFragment currentPage = (VideoFragment)mVideoFragmentPagerAdapter.getFragment(mCurrentPagerIndex);
if (currentPage != null) {
currentPage.pause();
}
}
VideoFragment newPage = (VideoFragment) mVideoFragmentPagerAdapter.getFragment(i);
if (newPage != null) {
newPage.playVideo();
}
mCurrentPagerIndex = i;
}
@Override
public void onPageScrollStateChanged(int state) {
}
...
/* part of the adapter implementation */
....
private Map<Integer, Fragment> mPageReferenceMap = new HashMap<Integer, Fragment>();
public Fragment getItem(int i) {
VideoFragment fragment = VideoFragment.newInstance(i, video);
mPageReferenceMap.put(i, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
mPageReferenceMap.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
2.如果我尝试快速滑动,则UI在页面过渡期间冻结了几秒钟,就像您在屏幕上并排看到的是两个页面一样.有时,我得到应用程序没有响应的错误,并在Logcat输出中看到各种错误和警告,但并非总是如此:
2. UI freezes for seconds during the page transition if I attempt to swipe through quickly, as in you literally see two pages on the screen side by side. Sometimes I get application not responding error and see various errors and warnings in Logcat output but it doesn’t happen all the time:
I/Choreographer﹕ Skipped 169 frames! The application may be doing too much work on its main thread.
…
W/System.err﹕ java.lang.IllegalArgumentException: The surface has been released
W/System.err﹕ at android.media.MediaPlayer._setVideoSurface(Native Method)
W/System.err﹕ at android.media.MediaPlayer.setDisplay(MediaPlayer.java:688)
W/System.err﹕ at com.fbwmedia.AFV.fragments.VideoFragment.playVideo(VideoFragment.java:232)
W/System.err﹕ at com.fbwmedia.AFV.activities.VideosActivity.onPageSelected(VideosActivity.java:145)
W/System.err﹕ at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:572)
….
E/MediaPlayer﹕ Attempt to call getDuration without a valid mediaplayer
E/MediaPlayer﹕ error (-38, 0)
在片段上实现playVideo():
implementation of playVideo() on Fragment:
public void playVideo() {
mMediaController.setEnabled(true);
mMediaController.setMediaPlayer(this);
mMediaController.setAnchorView(this.getView().findViewById(R.id.layout_video_player));
AudioManager am = (AudioManager) this.getActivity().getSystemService(Context.AUDIO_SERVICE);
am.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
try {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
} else {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
mMediaPlayer.reset();
}
mMediaPlayer.setDataSource(mPath);
mMediaPlayer.setDisplay(mHolder);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnCompletionListener(this);
wasPlayStarted = true;
isPrepared = false;
} catch (Exception e) {
e.printStackTrace();
}
}
public void onPrepared(MediaPlayer mediaplayer) {
mWidth = mediaplayer.getVideoWidth();
mHeight = mediaplayer.getVideoHeight();
if (mWidth != 0 && mHeight != 0 && this.getView() != null) {
setVideoProgressContentVisibility(View.GONE);
mHolder.setFixedSize(mWidth, mHeight);
mMediaPlayer.start();
mMediaController.show();
}
}
public void pause() {
if (mMediaPlayer != null && isPlaying()) {
mMediaPlayer.pause();
}
}
我怀疑视频播放器的准备过程正在阻塞UI线程,从而导致应用程序无响应.尽管我真的没有办法解决它,为什么它偶尔会引发Surface被释放错误而不是不是每次都抛出错误?
I'm suspecting that the process of preparing video player is blocking the UI thread causing the application not responding. Though I really ran out of ideas how to fix it and why it occasionally throwing the Surface being released error but not every time?
推荐答案
我的建议是仅使用一个MediaPlayer,而不是为每个页面创建一个.
My suggestion is to use only one MediaPlayer, instead of creating one for each page.
当页面滚动到中心时,可以加载其视频,并将其SurfaceView设置为页面中的视图.
You can load its video when a page is scrolled to center, and set its SurfaceView to the view in your page.
当视图将要移出当前页面时,您停止视频,重置MediaPlayer设置新的SurfaceView并准备下一个视频.
When a view is about to move out of current page, you stop the video, reset the MediaPlayer set new SurfaceView and prepare the next video.
您还需要考虑使用计时器来延迟onPageSelected的调用,以避免用太多的准备调用来干扰MediaPlayer.
You also need to consider using a timer to delay the call from onPageSelected in order to avoid hammering MediaPlayer with too many prepare calls.
例如:
onPageSelected() {
if (timer != null) {
timer.cancel();
}
timer = new Timer(new TimerRunnable() {
mediaPlayer.prepare(....
}......
}
这篇关于ViewPager上的Android MediaPlayer阻止UI转换并且初始页面加载没有回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!