You could try setting alpha channel of video view to 0 or close to 0.
VideoView onPrepared is not called if the VideoView is invisible
-
02-10-2022 - |
Question
I am hiding the VideoView
initially and when the video is loaded I am showing the VideoView
. But onPrepared
is never called if the VideoView
is invisible
initially. However onPrepared
is called properly if VideoView
is visible. Is there any way to hide the videoView
until video is loaded. Any help would be appreciated. Thanks!
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:visibility="invisible" />
</RelativeLayout>
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VideoView videoView = (VideoView) findViewById(R.id.video);
Uri videoUri = Uri.parse(url);
videoView.setVideoURI(videoUri);
videoView.requestFocus();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Toast.makeText(mActivity, "on prepared", Toast.LENGTH_SHORT).show();
videoView.setVisibility(View.VISIBLE);
}
});
}
Solution
OTHER TIPS
Solved it making its layout invisible instead of videoView itself. Thanks to @J.Kowalski .
Layout:
<FrameLayout
android:id="@+id/layout_video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:scrollbars="none"/>
</FrameLayout>
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
/>
Set OnPreparedListener:
videoView.setOnPreparedListener(this);
Show progress bar before ready:
@Override
public void showProgress() {
progress.setVisibility(View.VISIBLE);
layoutVideoView.setVisibility(View.INVISIBLE);
}
Load video URI:
@Override
public void loadVideo(Uri uri) {
videoView.setVideoURI(uri);
}
When its ready, onPrepared is called:
@Override
public void onPrepared(MediaPlayer mp) {
Log.d("debug", "onPrepared");
iStepPreviewPresenter.onVideoViewReady();
}
Finally show layout and start video:
@Override
public void hideProgress() {
progress.setVisibility(View.INVISIBLE);
layoutVideoView.setVisibility(View.VISIBLE);
}
@Override
public void startVideo() {
videoView.start();
}
Nailed it!
It can be achieved by one of these tricks
You can set the height and width of the
VideoView
to1px
until the video is prepared and then switch to full screen by changing the properties tomatch parent
As @FDIM said in his answer, we can set the alpha value of the view to 0 until video is prepared. But it works only if we use TextureView to load the video. It doesn't work with normal
VideoView
. Here is a custom VideoView extendingTextureView
which mimics the defaultVideoVideo
implementation. This class can be directly used in xml file and can set the alpha to 0 to hide the video.public class TextureVideoView extends TextureView implements SurfaceTextureListener { private MediaPlayer mMediaPlayer; public TextureVideoView(Context context) { super(context); init(); } public TextureVideoView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mMediaPlayer = new MediaPlayer(); this.setSurfaceTextureListener(this); } public void seekTo(int msec) { mMediaPlayer.seekTo(msec); } public void setVideoPath(final String path) throws IOException { mMediaPlayer.reset(); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); } public void setVideoPath(FileDescriptor fd, long offset, long length) throws IOException { mMediaPlayer.reset(); mMediaPlayer.setDataSource(fd, offset, length); mMediaPlayer.prepare(); } public void setVideoURI(Context context, Uri uri) throws IOException { mMediaPlayer.reset(); mMediaPlayer.setDataSource(context, uri); } public void setOnPreparedListener(OnPreparedListener onPreparedListener) { mMediaPlayer.setOnPreparedListener(onPreparedListener); } public void setOnCompletionListener(OnCompletionListener onCompletionListener) { mMediaPlayer.setOnCompletionListener(onCompletionListener); } public void setOnErrorListener(OnErrorListener onErrorListener) { mMediaPlayer.setOnErrorListener(onErrorListener); } public void start() { mMediaPlayer.start(); } public void pause() { mMediaPlayer.pause(); } public void setVolume(float leftVolume, float rightVolume ) { mMediaPlayer.setVolume(leftVolume, rightVolume); } public boolean isPlaying() { return mMediaPlayer.isPlaying(); } public void stopPlayback() { mMediaPlayer.stop(); } public void reset() { mMediaPlayer.reset(); } public void release() { mMediaPlayer.release(); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mMediaPlayer.setSurface(new Surface(surface)); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
An easier workaround:
Just add a dummy parentview
for the videoview
and set the visiblity
for that parentview
instead of changing the visibility
of the videoview
itself.