Android中VideoView播放前出现黑屏闪烁问题求助
引导视频播放前黑屏闪烁问题解决方案
问题场景
应用启动引导页包含视频引导内容,但视频播放前会出现短暂黑屏闪烁,常规方案无法解决,相关代码如下:
Java代码
@NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = layoutInflater.inflate(R.layout.slider_layout, container, false); ImageView slideImageView = view.findViewById(R.id.imageView); VideoView slideVideoView = view.findViewById(R.id.videoView); TextView slideHeading = view.findViewById(R.id.textTitle); TextView slideDescription = view.findViewById(R.id.textDescription); MediaItem item = mediaItems[position]; if (item.getType() == MediaItem.MediaType.IMAGE) { slideImageView.setImageResource(item.getResourceId()); slideImageView.setVisibility(View.VISIBLE); slideVideoView.setVisibility(View.GONE); } else if (item.getType() == MediaItem.MediaType.VIDEO) { slideImageView.setVisibility(View.GONE); slideVideoView.setVisibility(View.VISIBLE); // Set the video URI using the resource ID Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + item.getResourceId()); slideVideoView.setVideoURI(videoUri); // Start video playback when it's ready slideVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { slideVideoView.start(); } }); } slideHeading.setText(headings[position]); slideDescription.setText(descriptions[position]); container.addView(view); return view; }
XML布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/background_color" android:padding="16dp"> <SurfaceView android:layout_width="0px" android:layout_height="0px" android:visibility="gone" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp"> <VideoView android:id="@+id/videoView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" /> </FrameLayout> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="210dp" android:layout_gravity="center_horizontal" android:layout_marginTop="100dp" android:src="@drawable/baseline_image_24" /> <TextView android:id="@+id/textTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="24sp" android:textColor="@android:color/white" android:textAlignment="center" android:paddingTop="16dp" android:text="@string/heading_1" /> <TextView android:id="@+id/textDescription" android:textAlignment="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="16sp" android:textColor="@android:color/white" android:paddingTop="8dp" android:text="@string/description_1" /> </LinearLayout>
解决方案
方案1:用视频第一帧做占位图
在视频准备完成前,显示视频第一帧作为临时占位,避免黑屏:
- 提前提取视频第一帧保存为drawable资源(如
@drawable/video_guide_thumbnail) - 修改视频类型处理代码:
else if (item.getType() == MediaItem.MediaType.VIDEO) { // 先显示占位图 slideImageView.setImageResource(R.drawable.video_guide_thumbnail); slideImageView.setVisibility(View.VISIBLE); slideVideoView.setVisibility(View.INVISIBLE); Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + item.getResourceId()); slideVideoView.setVideoURI(videoUri); slideVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { // 视频准备好后切换显示 slideImageView.setVisibility(View.GONE); slideVideoView.setVisibility(View.VISIBLE); slideVideoView.start(); // 开启屏幕常亮,避免渲染延迟 mp.setScreenOnWhilePlaying(true); } }); // 监听视频开始渲染事件,确保完全加载后再显示 slideVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() { @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) { slideVideoView.setVisibility(View.VISIBLE); return true; } return false; } }); }
方案2:统一布局背景与尺寸
- 给VideoView设置和页面一致的背景色,避免加载时显示默认黑色:
<VideoView android:id="@+id/videoView" android:layout_width="match_parent" android:layout_height="210dp" android:layout_gravity="center" android:background="@color/background_color" />
- 调整FrameLayout尺寸和ImageView一致,避免布局重绘闪烁:
<FrameLayout android:layout_width="match_parent" android:layout_height="210dp" android:layout_marginTop="100dp" android:background="@color/background_color"> <VideoView android:id="@+id/videoView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:background="@color/background_color" /> </FrameLayout>
方案3:替换为ExoPlayer
VideoView的底层兼容性问题较多,改用ExoPlayer可更好控制播放流程:
- 添加依赖(替换为最新版本号):
implementation "com.google.android.exoplayer:exoplayer-core:2.19.1" implementation "com.google.android.exoplayer:exoplayer-ui:2.19.1"
- 替换布局中的VideoView为PlayerView:
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/playerView" android:layout_width="match_parent" android:layout_height="210dp" android:layout_marginTop="100dp" android:background="@color/background_color" />
- 修改Java代码实现播放:
else if (item.getType() == MediaItem.MediaType.VIDEO) { slideImageView.setVisibility(View.GONE); PlayerView playerView = view.findViewById(R.id.playerView); playerView.setVisibility(View.VISIBLE); // 初始化ExoPlayer SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); playerView.setPlayer(player); // 设置视频源 Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + item.getResourceId()); com.google.android.exoplayer2.MediaItem mediaItem = com.google.android.exoplayer2.MediaItem.fromUri(videoUri); player.setMediaItem(mediaItem); // 设置占位图 playerView.setDefaultArtwork(BitmapFactory.decodeResource(context.getResources(), R.drawable.video_guide_thumbnail)); // 准备并播放 player.prepare(); player.setPlayWhenReady(true); // 页面销毁时释放资源(需在instantiateItem对应的destroyItem中处理) player.addListener(new Player.Listener() { @Override public void onPlaybackStateChanged(int playbackState) { if (playbackState == Player.STATE_ENDED) { // 处理播放完成逻辑 } } }); }
内容的提问来源于stack exchange,提问作者AKD2022
相关产品推荐
相关产品推荐

