You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:17:35