【发布时间】:2014-08-21 08:53:05
【问题描述】:
基本上,我们想构建一个分页的水平滚动视图,每个页面上都有一个视频播放器;当页面焦点改变时,视频应该自动播放和自动暂停/停止。所以我决定使用 ViewPager 来显示视频片段。每个片段都有自己的 SurfaceView 和 MediaPlayer 用于视频播放。目标是在初始页面加载和用户滑动选择新页面时自动播放视频。
我面临一些问题:
- 加载初始页面时,我无法从 ViewPager 获得回调。我尝试实现 ViewPager.OnPageChangeListener 以暂停前一页上的视频并尝试在新选择的页面上播放视频。但是,当加载索引为 0 的页面作为初始页面时,不会调用“onPageSelected”。有谁知道还有另一种方法可以回调初始页面加载?
这是我的 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 输出中看到各种错误和警告,但并非一直发生:
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)
在 Fragment 上实现 playVideo():
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 being released 错误但不是每次都抛出?
【问题讨论】:
-
你能说明你为什么使用这个 VideoFragment newPage = (VideoFragment) mVideoFragmentPagerAdapter.getFragment(i);两次忘记最后一个 getFragment
-
您的意思是在方法 onPageSelected() 中吗?第一个 getFragment(mCurrentPagerIndex) 是获取即将离开屏幕的片段,以便我可以调用暂停视频,第二个 getFragment(i) 是调用开始播放视频。
标签: android-viewpager media-player android-mediaplayer surfaceview