Android 单VideoFragment实现CardView点击播放不同视频
运动教程多Card跳转单VideoFragment实现方案
问题核心原因
MediaController初始化要求传入Context类型参数,Fragment本身不是Context,直接传this会触发类型不匹配报错- 布局加载错误是
onCreateView中inflate方法传入了错误的布局id,参数传递未使用Fragment标准Bundle传参机制,导致无法根据点击项加载对应视频
完整实现代码
1. VideoFragment 核心逻辑修复
统一用静态newInstance方法处理传参,修复布局加载、MediaController初始化问题,补充生命周期逻辑避免内存泄漏
public class VideoFragment extends Fragment { // 传参Key常量,避免硬编码拼写错误 private static final String ARG_VIDEO_RES_ID = "arg_video_res_id"; private static final String ARG_SPORT_NAME = "arg_sport_name"; private VideoView videoView; private int currentVideoResId; private String currentSportName; // 静态实例化方法,外部跳转统一调用此方法传参 public static VideoFragment newInstance(int videoResId, String sportName) { VideoFragment fragment = new VideoFragment(); Bundle args = new Bundle(); args.putInt(ARG_VIDEO_RES_ID, videoResId); args.putString(ARG_SPORT_NAME, sportName); fragment.setArguments(args); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 修复:加载正确的fragment_video布局,替换之前错误的fragment_exercise View root = inflater.inflate(R.layout.fragment_video, container, false); // 读取传入的参数 if (getArguments() != null) { currentVideoResId = getArguments().getInt(ARG_VIDEO_RES_ID); currentSportName = getArguments().getString(ARG_SPORT_NAME); } videoView = root.findViewById(R.id.video_view); initPlayer(); return root; } private void initPlayer() { // 修复:传入requireContext()获取宿主Activity上下文,不再直接传this MediaController mediaController = new MediaController(requireContext()); mediaController.setAnchorView(videoView); videoView.setMediaController(mediaController); // 拼接raw资源下对应视频的URI Uri videoUri = Uri.parse("android.resource://" + requireContext().getPackageName() + "/" + currentVideoResId); videoView.setVideoURI(videoUri); // 准备完成后自动播放 videoView.setOnPreparedListener(mp -> videoView.start()); // 绑定返回按钮逻辑,点击回到运动列表页 mediaController.setPrevNextListeners(null, v -> { if (getParentFragmentManager() != null) { getParentFragmentManager().popBackStack(); } }); } // 页面不可见时暂停播放 @Override public void onPause() { super.onPause(); if (videoView != null && videoView.isPlaying()) { videoView.pause(); } } // 页面销毁时释放播放器资源 @Override public void onDestroyView() { super.onDestroyView(); if (videoView != null) { videoView.stopPlayback(); videoView = null; } } }
2. ExerciseFragment Card点击跳转逻辑
抽离公共点击绑定方法,点击不同Card时传入对应视频参数,复用同一个VideoFragment
public class ExerciseFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_exercise, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 提前将8个运动教程视频放到res/raw目录下,文件名仅支持小写字母、数字、下划线 // 按自己布局中的CardView id、对应视频资源、运动名称绑定即可 bindCardEvent(view.findViewById(R.id.card_running), R.raw.running, "跑步教程"); bindCardEvent(view.findViewById(R.id.card_squat), R.raw.squat, "深蹲教程"); bindCardEvent(view.findViewById(R.id.card_pushup), R.raw.pushup, "俯卧撑教程"); bindCardEvent(view.findViewById(R.id.card_situp), R.raw.situp, "仰卧起坐教程"); bindCardEvent(view.findViewById(R.id.card_plank), R.raw.plank, "平板支撑教程"); bindCardEvent(view.findViewById(R.id.card_jumpjack), R.raw.jumpjack, "开合跳教程"); bindCardEvent(view.findViewById(R.id.card_lunge), R.raw.lunge, "箭步蹲教程"); bindCardEvent(view.findViewById(R.id.card_stretch), R.raw.stretch, "拉伸教程"); } private void bindCardEvent(CardView cardView, int videoResId, String sportName) { cardView.setOnClickListener(v -> { VideoFragment videoFragment = VideoFragment.newInstance(videoResId, sportName); requireActivity().getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container, videoFragment) .addToBackStack(null) // 加入返回栈,支持按返回键回到列表 .commit(); }); } }
注意事项
- 视频文件需要放在
res/raw目录下,没有该目录手动新建即可,文件命名不能包含大写字母、中文、空格、特殊符号,否则R文件无法正常识别资源 - 确认
fragment_video.xml中VideoView的id为video_view,宿主Activity中放置Fragment的容器id为fragment_container,和代码保持一致 - 如果需要播放网络视频,只需将传参的视频资源id替换为String类型的视频url,加载时调用
videoView.setVideoURI(Uri.parse(videoUrl))即可,同时在AndroidManifest.xml中添加网络权限<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者yeontan
相关产品推荐
相关产品推荐

