Reputation: 19
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.
I am facing a few issues:
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 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)
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();
}
}
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?
Upvotes: 2
Views: 1380
Reputation: 101
My suggestion is to use only one MediaPlayer, instead of creating one for each page.
You can load its video when a page is scrolled to center, and set its SurfaceView to the view in your page.
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.
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.
for example:
onPageSelected() {
if (timer != null) {
timer.cancel();
}
timer = new Timer(new TimerRunnable() {
mediaPlayer.prepare(....
}......
}
Upvotes: 1