Android初学之封装IJkplayer制作视频播放的Dialog

首先引入IJkplayer依赖:

//ijkPlayer 播放器框架依赖
    //required, enough for most devices.足够大部分机型使用
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
    // # Other ABIs: optional
//    implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
//    implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
//    implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
//    implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'

这里引入armv7a机型的依赖支持就可以啦,足以支持市面上大部分的机型。
IJkplayer GitHub地址:https://github.com/bilibili/ijkplayer
接着编写dialog布局:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:elevation="@dimen/dp_4"
    android:layout_height="280dp">
    
    <com.zc.customview.TextViewIcon
        android:id="@+id/delete_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/text_color_one"
        android:textSize="@dimen/dp_20"
        android:text=""
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="15dp"
        />
    <SurfaceView
        android:layout_marginTop="30dp"
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="4dp"/>
    <ProgressBar
        android:id="@+id/progress"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="6dp"
        android:progressDrawable="@drawable/progress_bg"
        style="?android:progressBarStyleHorizontal"/>
    <android.support.constraint.ConstraintLayout
        android:id="@+id/loading_layout"
        android:layout_width="@dimen/dp_100"
        android:layout_height="@dimen/dp_100"
        android:layout_centerInParent="true"
        android:visibility="visible"
        android:background="@drawable/loading_dialog_layout_bg">
        <ImageView
            android:id="@+id/progress_view"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="@id/loading_dialog_title_tv"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@drawable/ic_loading_default"
            />
        <TextView
            android:id="@+id/loading_dialog_title_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="正在加载"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="@id/progress_view"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_gravity="center_horizontal"
            android:textSize="@dimen/fifth_text_size"
            android:textColor="@color/white"/>
    android.support.constraint.ConstraintLayout>
RelativeLayout>

Android初学之封装IJkplayer制作视频播放的Dialog_第1张图片
接着编写主要的dialog代码:

package com.zc.customview;

import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ProgressBar;
import com.zc.road.R;
import com.zc.util.LogUtil;
import com.zc.util.RxToast;
import com.zc.util.Util;

import java.io.IOException;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
/**
 * 播放视频Dialog
 * @author zc
 */
public class VideoDialog implements SurfaceHolder.Callback,IMediaPlayer.OnBufferingUpdateListener,
        IMediaPlayer.OnCompletionListener,DialogInterface.OnDismissListener,View.OnClickListener,
        IMediaPlayer.OnPreparedListener,IMediaPlayer.OnInfoListener,IMediaPlayer.OnErrorListener{
    private SurfaceView surfaceView;
    private AlertDialog dialog;
    private IjkMediaPlayer mPlayer;
    private ProgressBar progressBar;
    /**视频路径*/
    private String videoUrl;
    /**计时服务*/
    private ScheduledExecutorService service;
    /**加载进店条layout*/
    private ConstraintLayout loadingLayout;
    /**加载进度条*/
    private ImageView loadingView;
    /**是否显示加载进度条*/
    private boolean isShowLoading;
    /**加载进度条旋转动画*/
    private RotateAnimation animation;
    /**是否第一次加载*/
    private boolean isStartLoading;
    /**
     * 显示dialog
     * @param context Context
     * @param videoUrl 视频url
     */
    public void show(Context context,String videoUrl){
        this.videoUrl = videoUrl;
        //初始化dialog
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setCancelable(false);
        //初始化自定义播放界面
        View view = LayoutInflater.from(context).inflate(R.layout.video_dialog_layout, null);
        surfaceView = view.findViewById(R.id.surfaceView);
        TextViewIcon imageView = view.findViewById(R.id.delete_icon);
        progressBar = view.findViewById(R.id.progress);
        loadingLayout = view.findViewById(R.id.loading_layout);
        loadingView = view.findViewById(R.id.progress_view);
        progressBar.setMax(100);
        imageView.setOnClickListener(this);
        //dialog指定显示内容
        builder.setView(view);
        dialog = builder.create();
        dialog.setOnDismissListener(this);
        dialog.show();
        Window window = dialog.getWindow();
        //设置背景透明
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.gravity = Gravity.CENTER;
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = dp2px(280);
        //设置dialog大小
        window.setAttributes(lp);
        surfaceView.getHolder().addCallback(this);
    }

    /**
     * dp转px
     * @param dpValue dp值
     * @return Int
     */
    private int dp2px(final float dpValue) {
        final float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        initPlayer();
        mPlayer.setDisplay(surfaceView.getHolder());
    }

    /**
     * 初始化Player
     */
    private void initPlayer() {
        if (mPlayer == null) {
            mPlayer = new IjkMediaPlayer();
            //设置播放监听
            mPlayer.setOnInfoListener(this);
            //设置缓冲监听
            mPlayer.setOnBufferingUpdateListener(this);
            //设置播放完成监听
            mPlayer.setOnCompletionListener(this);
            // 设置倍速,MediaPlayer是不支持的
            mPlayer.setSpeed(1.0f);
            //设置加载好视频自动播放
            mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mPlayer.setOnPreparedListener(this);
            //设置播放错误监听
            mPlayer.setOnErrorListener(this);
            try {
                if (TextUtils.isEmpty(videoUrl)){
                    RxToast.warning("视频路径为空");
                    dialog.dismiss();
                    return;
                }
                mPlayer.setDataSource(videoUrl);
            } catch (IOException e) {
                RxToast.warning("视频路径错误");
                dialog.dismiss();
                e.printStackTrace();
            }
            mPlayer.prepareAsync();
            isStartLoading = true;
            showLoading();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (surfaceView != null) {
            surfaceView.getHolder().removeCallback(this);
            surfaceView = null;
        }
    }

    /**
     * 缓存进度
     * @param iMediaPlayer 播放器
     * @param i 进度
     */
    @Override
    public void onBufferingUpdate(IMediaPlayer iMediaPlayer, int i) {
        if (progressBar != null) {
            progressBar.setSecondaryProgress(i);
            //这里Ijkplayer有个缓冲问题  缓冲进度到达95以上就不执行该方法了  所以设置大于98时就缓冲完成
            if (i>=98){
                progressBar.setSecondaryProgress(100);
            }
        }
    }

    /**
     * 视频播放完成关闭dialog
     * @param iMediaPlayer  IMediaPlayer
     */
    @Override
    public void onCompletion(IMediaPlayer iMediaPlayer) {
        if (dialog != null) {
            dialog.dismiss();
        }
        clearTimeService();
    }

    /**
     * 释放关闭Player
     */
    private void release() {
        if (mPlayer != null) {
            mPlayer.stop();
            mPlayer.release();
            mPlayer = null;
        }
        IjkMediaPlayer.native_profileEnd();
    }

    /**
     * dialog消失回调方法 在这里处理释放player  关闭加载动画
     * @param dialog  DialogInterface
     */
    @Override
    public void onDismiss(DialogInterface dialog) {
        release();
        clearTimeService();
        if (animation != null) {
            if (isShowLoading){
                animation.cancel();
            }
            animation = null;
        }
    }

    /**
     * 点击关闭dialog
     * @param v View
     */
    @Override
    public void onClick(View v) {
        if (dialog!=null && dialog.isShowing()){
            dialog.dismiss();
        }
    }

    @Override
    public void onPrepared(IMediaPlayer iMediaPlayer) {
        if (mPlayer != null) {
            //开始播放
            mPlayer.start();
        }
        if (service == null) {
            //计时服务
            service = new ScheduledThreadPoolExecutor(1);
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    if (mPlayer != null) {
                        //获取百分比显示进度条
                        int percent = (int) (mPlayer.getCurrentPosition()*100 / mPlayer.getDuration());
                        progressBar.setProgress(percent);
                    }
                }
            };
            service.scheduleAtFixedRate(task,10,1000, TimeUnit.MILLISECONDS);
        }
    }

    /**
     * 关闭计时服务
     */
    private void clearTimeService(){
        if (service != null) {
            service.shutdownNow();
            service = null;
        }
    }

    /**
     * 播放监听回调
     * @param iMediaPlayer IMediaPlayer
     * @param i 当前状态码
     * @param i1 之前状态码
     * @return boolean
     */
    @Override
    public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) {
        LogUtil.logNormalMsg("VideoDialog", "------------onInfo--------i:"+i);
        //当视频由于网速差加载卡顿时返回状态码701(多次测试得知,未查阅官方文档)
        if (i==701){
            isShowLoading = true;
        }else {
            isShowLoading = false;
        }
        isStartLoading = false;
        //判断是否显示加载进度条
        showLoading();
        return false;
    }

    private void showLoading() {
        if (isShowLoading || isStartLoading){
            //显示加载进度条
            Util.showView(loadingLayout,true);
            if (animation == null){
                //初始化进度条旋转动画
                animation =  new RotateAnimation(0,360*74, Animation.RELATIVE_TO_SELF,
                        0.5f,Animation.RELATIVE_TO_SELF,0.5f);
                animation.setDuration(75000);
                animation.setRepeatCount(1);
                animation.setFillAfter(true);
                animation.setInterpolator(new LinearInterpolator());
                loadingView.startAnimation(animation);
            }
        }else {
            //隐藏加载进度条  关闭动画
            if (animation != null) {
                animation.cancel();
                animation = null;
            }
            Util.showView(loadingLayout,false);
        }
    }

    @Override
    public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
        switch (i){
            case -10000:
                //视频连接超时
                if (dialog != null && dialog.isShowing()) {
                    dialog.dismiss();
                }
                RxToast.showTips("视频连接超时,请检查路径是否正确");
                break;
                default:
                    //do nothing
                    break;
        }
        return false;
    }
}

在activity或fragment调用dialog.show()方法播放:

VideoDialog videoDialog = new VideoDialog();
videoDialog.show(this,videoUrl);

最终效果:

注:网速差导致视频卡顿时返回的状态码为701,这个状态码是多次测试得出的结论,并非官方文档中得出的,若有人知道具体状态码还望告知,谢谢!

你可能感兴趣的:(Android笔记)