【安卓】视频播放器实现过程,超详细注释,自定义视频进度条,打开本地文件播放视频等功能。

一、实现效果


废话不多说,直接上代码,里面有详细注释,不清楚的评论区留言。

二、布局代码


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:background="@color/background"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical">
        <ImageButton
            android:id="@+id/video_file"
            android:layout_width="12dp"
            android:layout_height="12dp"
            android:background="@mipmap/video_file"/>
        <TextView
            android:id="@+id/open_video"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:clickable="true"
            android:textSize="8dp"
            android:text="本地视频"/>
    LinearLayout>

    <VideoView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_marginLeft="3dp"
        android:layout_alignParentBottom="true"
        android:gravity="center_vertical"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/play_video"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:text="播放"
            android:textColor="@color/white"
            android:layout_weight="2"
            android:textSize="10dp"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text=" | "/>
        <TextView
            android:id="@+id/pause_video"
            android:layout_width="0dp"
            android:clickable="true"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text="暂停"
            android:textColor="@color/white"
            android:textSize="10dp"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text=" | "/>
        <TextView
            android:id="@+id/replay_video"
            android:layout_width="0dp"
            android:clickable="true"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text="重播"
            android:textColor="@color/white"
            android:textSize="10dp"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text=" | "/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/seekbar_start_second"
            android:text="0"
            android:textSize="8dp"
            android:layout_weight="1"
            android:textColor="@color/white"/>
        <SeekBar
            android:layout_width="0dp"
            android:id="@+id/seekbar_video"
            android:layout_height="wrap_content"
            android:layout_weight="60"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/seekbar_max_second"
            android:text="0"
            android:textSize="8dp"
            android:layout_weight="1"
            android:textColor="@color/white"/>
    LinearLayout>
RelativeLayout>

三、Activity代码

package com.example.tabtest.activity;

import android.app.Activity;;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.VideoView;
import com.example.tabtest.R;
import com.example.tabtest.util.FormatTime;

/**
 * author lishilin
 * date 2023-7-25
 * 描述 视频播放器,自定义播放进度条,可以打开文件管理器选择本地视频进行播放
 */

public class VideoActivity extends Activity implements View.OnClickListener {
    private VideoView video;
    private TextView startPlay;
    private TextView pausePlay;
    private int totalSeconds;//视频总时长,单位,毫秒
    private int currentSeconds;//当前视频进度
    private int seekBarMax;//进度条最大值
    private SeekBar seekBar;//进度条
    private TextView seekBarMaxSecond;//进度条最大秒数
    private TextView seekBarStartSecond;//进度条开始秒数
    private FormatTime formatTime;
    private TextView replay;
    private TextView openVideo;
    private ImageButton videoFile;
    @Override
    public void onCreate(Bundle saveInstanceState){
        super.onCreate(saveInstanceState);
        setContentView(R.layout.video_play);
        initView();
        formatTime = new FormatTime();
        updateSeekbar();//监听进度条滑块
        playListener();//设置视频加载监听器
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制页面横屏
    }

    /**
     * 点击事件
     * @param view
     */
    @Override
    public void onClick(View view){
        switch (view.getId()){
            case R.id.play_video:
                if (!video.isPlaying()){
                    video.start();
                }
                break;
            case R.id.pause_video:
                if (video.isPlaying()){
                    video.pause();
                }
                break;
            case R.id.replay_video:
                video.resume();
                break;
            case R.id.open_video:
            case R.id.video_file:
                toOpenVideo();
                break;
            default:
                break;
        }
    }

    /**
     * 初始化组件
     */
    private void initView(){
        video = (VideoView) findViewById(R.id.video);
        String videoPath = "https://vfx.mtime.cn/Video/2019/07/12/mp4/190712140656051701.mp4";//网络视频地址
        video.setVideoPath(videoPath);
//        Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.test); //本地视频地址
//        video.setVideoURI(uri);//设置视频播放路径
        video.requestFocus();//视频获取焦点
        seekBar = (SeekBar) findViewById(R.id.seekbar_video);
        seekBarMaxSecond = (TextView) findViewById(R.id.seekbar_max_second);
        seekBarStartSecond = (TextView) findViewById(R.id.seekbar_start_second);
        replay = (TextView) findViewById(R.id.replay_video);
        replay.setOnClickListener(this);
        startPlay = (TextView) findViewById(R.id.play_video);
        pausePlay = (TextView) findViewById(R.id.pause_video);
        openVideo = (TextView) findViewById(R.id.open_video);
        videoFile = (ImageButton) findViewById(R.id.video_file);
        videoFile.setOnClickListener(this);
        openVideo.setOnClickListener(this);
        startPlay.setOnClickListener(this);
        pausePlay.setOnClickListener(this);
    }
    /**
     * 设置视频播放时候的动作监听,并作出相应的处理,比如进度条更新等操作
     */
    private void playListener(){
        //监听视频准备加载完毕之后执行
        video.setOnPreparedListener(mediaPlayer -> {
            video.start();
            totalSeconds = video.getDuration();//获取视频总毫秒数
            seekBarMaxSecond.setText(formatTime.SecondToTime(totalSeconds/1000));//设置进度条最大时间秒数
            seekBarMax = totalSeconds;
            seekBar.setMax(seekBarMax);
            //异步更新ui,利用消息机制处理子线程的需求
            Handler mhandler = new Handler(){
                @Override
                public void handleMessage(Message message){
                    if(message.what == 1){
                        updateProcess();//更新视频播放时间和进度条
                    }
                }
            };
            //子线程里执行循环发送消息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    currentSeconds = video.getCurrentPosition();//获取视频播放进度,返回值为毫秒
                    while (true){
                        Message message = new Message();
                        message.what = 1;
                        mhandler.sendMessage(message);
                        try {
                            Thread.sleep(1);//设置一毫秒更新一次进度条ui,这里可以改成想要的值
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        });
    }

    /**
     * 更新视频播放时间和进度条
     */
    private void updateProcess(){
        currentSeconds = video.getCurrentPosition();
        seekBarStartSecond.setText(formatTime.SecondToTime(currentSeconds/1000));
        seekBar.setProgress(currentSeconds);
    }

    /**
     * 监听进度条滑块
     */
    public void updateSeekbar(){
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }
            //停止滑动的时候执行下面的方法
            @Override
            public void onStopTrackingTouch(SeekBar seekBar1) {
                int current = seekBar.getProgress();
                video.seekTo(current);
                seekBarStartSecond.setText(formatTime.SecondToTime(currentSeconds/1000));
            }
        });
    }

    /**
     * 打开视频文件并播放
     */
    private void toOpenVideo(){
        video.pause();
        Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");//设置类型,这是任意类型
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        //打开一个activity,并在onActivityResult方法里面接收回调数据,更新视频地址
        startActivityForResult(intent,1);
        //销毁上一个视频
        video.suspend();
    }

    private static final int FILE_SELECT_CODE = 1;

    /**
     * 处理打开文件之后的行为,如给video设置视频路径,该方法是activity在执行完startActivityForResult(intent,1)方法之后自动执行的,无需调用;
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(int requestCode,int resultCode,Intent data){
        if(resultCode == Activity.RESULT_OK){
            Uri uri = data.getData();
            video.setVideoURI(uri);
            video.requestFocus();
            super.onActivityResult(requestCode,resultCode,data);
            return;
        }
        if (resultCode == FILE_SELECT_CODE){
            Uri uri = data.getData();
            Log.d("videoActivity",uri.getPath());
        }
        super.onActivityResult(requestCode,resultCode,data);
    }

    @Override
    public void onDestroy() {
        video.suspend();
        Log.i("视频播放器","释放资源");
        super.onDestroy();
    }
}

自定义一个进度条时间转换工具类,超简单

public class FormatTime {
    public String SecondToTime(int seconds){
        int second = seconds % 60;
        int m = seconds / 60;
        int h = seconds /60 /60;
        return h+":"+m+":"+second;
    }
}

最后,布局资源有一个icon,自己网上找一个,或者删掉那个图标的ImageButton,颜色值啥的自己设置叭

你可能感兴趣的:(Android,android,音视频)