How to avoid flickering and black screen issues when using VideoView?
VideoView is the most straightforward way to show video content in layout.
It took a few lines of code to setup and show for example mp4 file.
It's fine when you don't care about UX too much, but when you do, things are going to be annoying.
When you tested app for different cases like: change device orientation, swipe the view, lock screen or go to home screen and back to the app, you probably know what I'm talking about.
If you don't, take a look at:
VideoView Black Screen
VideoView Black Flash Before and After Playing
VideoView Inside Fragment Causes Black Screen Flickering
VideoView Flickering Issue
Workaround
To deal with these problems we can use 'placeholder solution' described in the above links.
The idea is to show placeholder, which has the same color as video background, when VideoView
is not ready to show the content yet. When VideoView
is ready the placeholder will go away and already prepared video will be revealed without any issues.
Thereby we achieve nice solid experience, because user doesn't see how system prepares video to render it, which causes VideoView
displays black screen or the content flickering. If you want to observe these issues try to move the app to the background (by pressing home screen button) and bring back the app to the foreground.
If it still seems to work well, try it a couple of times... it will happen ;)
FrameVideoView
FrameVideoView
is a class which implements 'placeholder workaround' dynamically by creating views in runtime. You don't have to create additional layout for placeholder and put VideoView
in there nor have you to take care about showing and hiding placeholder in an appropriate time. FrameVideoView
does it for you.
If device is running API level 13 or below, VideoView
will be used to show video content. This approach should fix most of the flickering and black screen issues.
For devices running API level 14 or higher, TextureView
will be used to show video content. It provides a lot better performance than VideoView
implementation because it was created to show 'stream content' like video or OpenGL scenes.
I wrote app with ViewPager
where each of three fragments has different video and are playing simultaneously. When FrameVideoView
used VideoView
implementation there were problems because sometimes black screen issues appeared again when swiping. There was also the problem when user swiped to the last page and ViewPager
showed overscroll animation that can't overlay VideoView
. When TextureView
implementation was used all problems were gone and app worked as expected.
How to use it?
Add FrameVideoView
to layout:
<mateuszklimek.framevideoview.FrameVideoView
android:id="@+id/frame_video_view"
android:layout_width="@dimen/video_width"
android:layout_height="@dimen/video_height"
/>
find its instance in Activity
and call corresponding methods in onResume
and onPause
:
public class SampleActivity extends Activity {
private FrameVideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple);
String uriString = "android.resource://" + getPackageName() + "/" + R.raw.movie;
videoView = (FrameVideoView) findViewById(R.id.frame_video_view);
videoView.setup(Uri.parse(uriString), Color.GREEN);
}
@Override
protected void onResume() {
super.onResume();
videoView.onResume();
}
@Override
protected void onPause() {
videoView.onPause();
super.onPause();
}
}
If you want to execute method for particular implementation eg. seekTo()
from VideoView
you can call it like that:
frameVideoView.asVideoView().seekTo(x);
but before, it's better to check what type of implementation is used:
if(videoView.getImplType() == VIDEO_VIEW){
frameVideoView.asVideoView().seekTo(x);
}
I uploaded the project to Github so you can run example app and see full implementation of \FrameVideoView\\
. Feel free to use it as you like.
See this post on my personal blog.