Android Java与XML实现视频SeekBar及Intent获取Video Uri播放控制
Android 视频播放与SeekBar控制实现(Java+XML)
一、XML布局(activity_main.xml)
构建包含视频显示区域和进度控制条的布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 视频渲染区域 --> <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <!-- 进度控制条 --> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" android:layout_marginVertical="8dp" /> <!-- 操作按钮(选择视频/播放暂停) --> <Button android:id="@+id/btnPlayPause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="选择视频" /> </LinearLayout>
二、Java代码实现(MainActivity.java)
1. 核心变量定义
private SurfaceView surfaceView; private SeekBar seekBar; private Button btnPlayPause; private MediaPlayer mediaPlayer; private SurfaceHolder surfaceHolder; private Handler handler = new Handler(Looper.getMainLooper()); private boolean isPlaying = false; private static final int PICK_VIDEO_REQUEST = 1;
2. 初始化视图与事件监听
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定视图 surfaceView = findViewById(R.id.surfaceView); seekBar = findViewById(R.id.seekBar); btnPlayPause = findViewById(R.id.btnPlayPause); // 初始化SurfaceHolder,监听Surface生命周期 surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { // Surface创建后,给MediaPlayer设置显示载体 if (mediaPlayer != null) { mediaPlayer.setDisplay(holder); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface销毁时释放MediaPlayer资源,避免内存泄漏 if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } handler.removeCallbacks(updateSeekBarRunnable); } }); // 按钮点击逻辑:选择视频/切换播放暂停 btnPlayPause.setOnClickListener(v -> { if (!isPlaying) { // 打开系统文件选择器,筛选视频文件 Intent pickVideoIntent = new Intent(Intent.ACTION_GET_CONTENT); pickVideoIntent.setType("video/*"); startActivityForResult(pickVideoIntent, PICK_VIDEO_REQUEST); } else { togglePlayPause(); } }); // SeekBar拖动事件监听 seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // 用户主动拖动时,跳转到对应进度 if (fromUser && mediaPlayer != null) { mediaPlayer.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 开始拖动时暂停进度更新 handler.removeCallbacks(updateSeekBarRunnable); } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 停止拖动后恢复进度更新(如果视频正在播放) if (mediaPlayer != null && mediaPlayer.isPlaying()) { handler.postDelayed(updateSeekBarRunnable, 100); } } }); }
3. 处理视频选择结果
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICK_VIDEO_REQUEST && resultCode == RESULT_OK && data != null) { Uri videoUri = data.getData(); if (videoUri != null) { initMediaPlayer(videoUri); } } }
4. 初始化MediaPlayer并播放视频
private void initMediaPlayer(Uri videoUri) { try { // 先释放旧的MediaPlayer实例 if (mediaPlayer != null) { mediaPlayer.release(); } mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(this, videoUri); mediaPlayer.setDisplay(surfaceHolder); // 异步准备,避免阻塞UI线程 mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(mp -> { // 准备完成后设置SeekBar最大值并开始播放 seekBar.setMax(mp.getDuration()); mp.start(); isPlaying = true; btnPlayPause.setText("暂停"); // 启动进度更新任务 handler.postDelayed(updateSeekBarRunnable, 100); }); mediaPlayer.setOnCompletionListener(mp -> { // 视频播放完成后重置状态 isPlaying = false; btnPlayPause.setText("选择视频"); handler.removeCallbacks(updateSeekBarRunnable); seekBar.setProgress(0); }); } catch (IOException e) { e.printStackTrace(); } }
5. 播放/暂停切换逻辑
private void togglePlayPause() { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); btnPlayPause.setText("播放"); handler.removeCallbacks(updateSeekBarRunnable); } else { mediaPlayer.start(); btnPlayPause.setText("暂停"); handler.postDelayed(updateSeekBarRunnable, 100); } }
6. 定时更新SeekBar进度
private Runnable updateSeekBarRunnable = new Runnable() { @Override public void run() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { // 更新SeekBar当前进度 seekBar.setProgress(mediaPlayer.getCurrentPosition()); // 每100毫秒重复执行一次 handler.postDelayed(this, 100); } } };
7. 生命周期处理(避免资源泄漏)
@Override protected void onPause() { super.onPause(); // 页面暂停时暂停视频播放 if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); btnPlayPause.setText("播放"); } } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时彻底释放MediaPlayer和Handler资源 if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } handler.removeCallbacks(updateSeekBarRunnable); }
三、权限配置
在AndroidManifest.xml中添加必要的权限:
<!-- Android 12及以下读取存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13及以上读取视频媒体权限 --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
注意:Android 6.0及以上版本需要动态申请权限,可在打开文件选择前添加权限检查逻辑。
内容的提问来源于stack exchange,提问作者Harsha
相关产品推荐
相关产品推荐

