代码已经托管到码云,有兴趣的小伙伴可以下载看看

https://git.oschina.net/joy_yuan/MobilePlayer

一、设置视频缓冲进度

显示视频播放进度的效果图如下:灰色的是缓冲的进度。

wKioL1l2FEqzauzjAABHSNZTaSQ094.png-wh_50



原理:只有播放网络视频时,才有缓冲这个说法,所以要先判断视频资源是否为网络资源

/**
 * 判断是否是网络的资源
 * @param uri
 * @return
 */
public boolean isNetUri(String uri) {
    boolean reault = false;
    if (uri != null) {
        if (uri.toLowerCase().startsWith("http") || uri.toLowerCase().startsWith("rtsp") || uri.toLowerCase().startsWith("mms")) {
            reault = true;
        }
    }
    return reault;
}

因此在前面,不管是单个的URI还是通过list传来的mediaitem数组,都要根据地址来去判断,然后在handler里去设置进度条。

    进度条很简单,只需要设置seekbarVideo.setSecondaryProgress(int progress);即可达到设置进度。那么这个缓冲值怎么获取的呢,这个是一个统一的写法,没有什么原因,如下代码:

    

//网络资源缓冲
if (isNetUri){
    //只有网络资源有缓冲
    int bufferPercentage = videoview.getBufferPercentage();  //0~100
    int totalbuffer = bufferPercentage * seekbarVideo.getMax();
    int secordProgress=totalbuffer/100;
    seekbarVideo.setSecondaryProgress(secordProgress);
}else{
    //本地进度条没有缓冲,即第二条进度条为灰色
    seekbarVideo.setSecondaryProgress(0);
}
二、使播放本地视频时,可以跳出来选择自定义播放器的方法。
    当我们手机里装了多个播放器后,如果要播放本地视频,系统会跳出来一个选择框,让用户选择播放哪个视频
    这里用到里隐式意图,只要给SystemVideoPlayer这个activity在AndroidManifext.xml里配置隐式意图即可:
    

    
        

        
        

        
    
    
        
        

        
        
    
    
        

        
        

        
        
        
        
        
    

    
        

        
        
        

        
        
        
        
        
        
        
        
        
        
        
    
    
        

        

        
    
    
        

        
        

        
    
    
        

        
        

        
        
        
        
        
    
    
        
        
        

        

        
        
        
    
    
        

        
        

        
        
    
    
        

        
        

        
        
        
        
        
        
        
        
        
        
        
        
        
    
    
        

        
        

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
        

        
        

        
        
    
    
        
        
        
        
    
    
        
        
        
        
        
    
    
        
        
        
    
    
        
        
        
        
    
    
        
        
    



三、监听视频播放卡顿时,弹出一个progressbar并提示用户当前网速

    在这里就要写一个布局,与视频播放布局在同一个布局,同样是include进来

    在system_video_player.xml里加入

    3.1 buffering.xml

    



    

    

    3.2 视频卡顿时,在Android4.2.2后,系统集成进到了videoview里了,作为一个监听,那么我们只要实现了这个监听就可以在里面获取卡顿时与不卡顿时的回调方法:

    

//监听网络播放卡顿现象
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    videoview.setOnInfoListener(new MyOnInfoListener());
}


/**
 * 视频播放卡顿时的监听,Android4.2.2后封装到了videoview里了已经
 */
public class MyOnInfoListener implements MediaPlayer.OnInfoListener

{
    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what){
            case MediaPlayer.MEDIA_INFO_BUFFERING_START: //开始卡顿
                //显示卡顿的布局
                buffering.setVisibility(View.VISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:  //结束卡顿
                buffering.setVisibility(View.GONE);
                break;
        }
        return true;
    }
}

这时候,只要是卡顿了,那么就会弹出一个progressbar在视频中央


  3.3 在上面的这个,是系统集成好的判断是否卡顿的方法,那么我们也可以自定义判断视频是否卡顿,

    原理是:在handler每一秒循环的消息体中,去判断当前视频进度和上一次循环消息时的视频进度相减,如果进度小鱼500ms,那么就判断是卡顿了,否则就不卡。

    

if (videoview.isPlaying()){
    int buffer=currentPosition-preCurrentPosition;
    if (buffer<500){
        //视频卡了
        buffering.setVisibility(View.VISIBLE);
    }else{
        buffering.setVisibility(View.GONE);
    }

}else{
    buffering.setVisibility(View.GONE);
}

preCurrentPosition=currentPosition;

    上面的代码也能判断视频卡顿时,显示progressbar。



四、视频播放前的loading布局与获取系统的网速

    原理:写一个布局,与视频播放页面system_video_player.xml在一个布局里,宽高都是match_parent即覆盖整个屏幕。这样当点击播放视频时,会先显示这个布局,然后我们再在视频准备好播放时,让这个布局消失,即可达到效果

    4.1 system_video_player.xml




    
    
    
    
    

    

4.2 在systemVideoPlayer.java里

    

public void onPrepared(MediaPlayer mp) {
    videoview.start(); //开始播放
    duration = videoview.getDuration();  //获取视频总时长
    seekbarVideo.setMax(duration);   //设置播放进度的最大值

    //发送消息,来更新视频进度
    handler.sendEmptyMessage(PROGRESS);

    //设置显示的视频总时长
    tvDuration.setText(utils.stringForTime(duration));

    //默认进入播放时,隐藏
    media_controller.setVisibility(View.GONE);
    isShow=false;  //设置为隐藏

    //获取播放器播放视频的宽度和高度
    videoHeight=mp.getVideoHeight();
    videoWidth=mp.getVideoWidth();
   // videoview.setVideoSize(mp.getVideoWidth(),mp.getVideoHeight());

    setVideoType(DEFAULTSCREEN);

    //当准备好播放时,把loading页面消失掉
    ll_loading.setVisibility(View.GONE);

}


4.2 获取网速

    原理是:每次handler2秒循环一次获取网速消息,在2秒内,获取的数据量/时间,即可得到网速。

具体代码如下:

/**
 * 得到网络速度
 * 每隔两秒调用一次
 * @param context
 * @return
 */
public String getNetSpeed(Context context) {
    String netSpeed = "0 kb/s";
    long nowTotalRxBytes = TrafficStats.getUidRxBytes(context.getApplicationInfo().uid)==TrafficStats.UNSUPPORTED ? 0 :(TrafficStats.getTotalRxBytes()/1024);//转为KB;
    long nowTimeStamp = System.currentTimeMillis();
    long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换

    lastTimeStamp = nowTimeStamp;
    lastTotalRxBytes = nowTotalRxBytes;
    netSpeed  = String.valueOf(speed) + " kb/s";
    Log.d(TAG, "当前总的数据"+nowTotalRxBytes);
    return  netSpeed;
}

这里要在loading布局声明好时,就立刻发消息,去handler处理,来获取网速,以便loading界面也出现网速显示。

    

//加载布局时的布局与网速显示
ll_loading= (LinearLayout) findViewById(R.id.ll_loading);
tv_loading_netspeed= (TextView) findViewById(R.id.tv_loading_netspeed);

handler.sendEmptyMessage(SPEED);  //控件只要一声明好就发消息去获取网速


发完声明后,就在handler里去处理消息,获取网速,然后在loading和卡顿时,显示网速,不卡顿时,隐藏对应的布局

    

public Handler handler=new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case SPEED:  //显示当前网速
                //得到网速
                String netSpeed = utils.getNetSpeed(SystemVideoPlayer.this);
                System.out.println("当前网速"+netSpeed);
                //显示网速
                tv_loading_netspeed.setText("玩命加载中"+netSpeed);  //loading时的速度显示
                tv_netspeed.setText("缓冲中"+netSpeed);  //缓冲时的速度显示
                removeMessages(SPEED);
                handler.sendEmptyMessageDelayed(SPEED,2000);  //一定要隔2秒才能去获取网速
                break;
                
         }
         
    };