Android-VideoView视频播放(视频第一帧,循环播放,隐藏播放条、横屏生命周期、缓存问题...)

大纲

* VideoView播放网络视频、播放本地视频

* 实现边播边缓存

* 获取视频的第一帧图片作为封面

* 实现类似朋友圈小视频循环播放

* 隐藏播放条

* 交互,点击屏幕退出播放

* 解决横屏生命周期重新加载的问题

* 加载时进度条的显示与消失监听 progressbar


videoview原型:
videoView extends SurfaceView implements MediaController.MediaPlayerControl
其中SurfaceView 为显示提供支持,MediaPlayerControl则为媒体控制提供了支持。
如果要构建更为复杂和有特色个性的视频View,需要继承SurfaceView 和实现MediaPlayerControl接口。


VideoView播放网络视频、播放本地视频

用videoview播放视频是非常简单的一件事,下面我放全代码,实现以下:
首先布局文件video_play_layout.xml中

    <VideoView
        android:id="@+id/videoPlayView"
        android:layout_width="match_parent"
        android:layout_height="240dp"
        android:layout_centerVertical="true" />

VideoPlayActivity.java中

public class VideoPlayActivity extends AppCompatActivity  {
    private VideoView videoView;
    private MediaController mc;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.video_play_layout);
        videoView = (VideoView) findViewById(R.id.videoPlayView);
        //设置视频控制器,组件可以控制视频的播放,暂停,快进,组件,不需要你实现
        mc = new MediaController(this);
        videoView.setMediaController(mc);
        String netPlayUrl="http://baobab.wdjcdn.com/145076769089714.mp4";
        Uri uri = Uri.parse(netPlayUrl);
        videoView.setVideoURI(uri);//设置视频的播放地址,网络地址。播放网络视频
        //播放本地视频
        videoView.setVideoPath(Environment.getExternalStorageDirectory().getPath()+"video.mp4");
        videoView.requestFocus();//让VideiView获取焦点  
        videoView.start();//开始播放
     }
}

调用VideoView的如下两个方法来加载指定的视频
setVidePath(String path):加载路径文件代表的视频
setVideoURI(Uri uri):加载uri所对应的视频
⚠️:加载网络视频的时候记得要在AndroidManifest.xml中加入权限:
<uses-permission android:name="android.permission.INTERNET" />


实现边播边缓存

视频缓存策略:
先加载,缓存到本地再播放,这适用于微信朋友圈这种小视频、若视频过大,肯定不能用这种。
边播放边缓存:对余大多数,还是使用边播边缓存的。

边播边缓存策略:

  • 第一种方法:开两个线程,一个去正常让videoview请求播放,另一个线程去下载文件,等到再次点击播放,此时如果视频以及有缓存,就播放本地缓存。(但是这种相当于两份网络请求,时间会变慢)
  • 第二种方法:通过代理的策略实现一个中间层将我们的网络请求转移到本地实现的代理服务器上,这样我们真正请求的数据就会被代理拿到,这样代理一边向本地写入数据,一边根据我们需要的数据看是读网络数据还是读本地缓存数据再提供给我们,真正做到了数据的复用。
    对于videoview,github开源上有一个写好的库实现边播边缓存
    地址:
    AndroidVideoCache
    AndroidVideoCache-视频边播放边缓存的代理策略

具体使用,是分简单,

compile 'com.danikula:videocache:2.7.0' //在app/build.gradle中加入依赖,引第三方

CustomViewApp.java

public class CustomViewApp extends Application {
    //全局初始化一个本地代理服务器
    private HttpProxyCacheServer proxy;

    public static HttpProxyCacheServer getProxy(Context context) {
        CustomViewApp app = (CustomViewApp) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }

    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer(this);
    }

}
VideoPlayActivity.java中:
    private VideoView videoView;
    private MediaController mc;
    private String proxyUrl;
    private HttpProxyCacheServer proxy;
   @Override
    protected void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState);
        setContentView(R.layout.video_play_layout);
        videoView = (VideoView) findViewById(R.id.videoPlayView);
        //设置视频控制器,组件可以控制视频的播放,暂停,快进,组件,不需要你实现
        mc = new MediaController(this);
        videoView.setMediaController(mc);
        String netPlayUrl="http://baobab.wdjcdn.com/145076769089714.mp4";
        proxy = CustomViewApp.getProxy(getApplicationContext());
        proxyUrl = proxy.getProxyUrl(netPlayUrl);
        videoView.setVideoPath(proxyUrl);//播放的是代理服务器返回的url,已经进行了封装处理
        videoView.requestFocus();//让VideiView获取焦点  
        videoView.start();//开始播放
}
....

AndroidManifest.xml中,因为application改变了,所以application标签中,
android:name=".CustomViewApp" ⚠️

此时播放的时候,可以看到缓存的进度条,明显的边播边加载,在加载完完整的一次后,再次打开就不会加载了,而是播放缓存的视频。具体原理想要深层探究可以看我上面的文章链接


获取视频的第一帧图片作为封面

类似朋友圈,播放前我们是需要一个封面图加一个按钮,单击按钮跳转到我们刚才写的activity中,

* a .服务端提供url,直接提供一个方法获得url,并使用glide库将url转换成图片

* b.若服务端不提供url,MediaMetadataRetriever 类提供了一个统一的接口用于从一个输入媒体文件中取得帧和元数据。API官方链接:http://developer.android.com/reference/android/media/MediaMetadataRetriever.html,使用这个类去取得第一帧图片:

Bitmap bitmap = null;
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
           try {

    //根据网络视频的url获取第一帧--亲测可用。但是这个方法获取本地视频的第一帧,不可用,还没找到方法解决。
            if (Build.VERSION.SDK_INT >= 14) {
                retriever.setDataSource(videoUrl, new HashMap<String, String>());
            } else {
                retriever.setDataSource(videoUrl);
            }
            //获得第一帧图片
            bitmap = retriever.getFrameAtTime();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            retriever.release();
        }
        return bitmap;


实现类似朋友圈小视频循环播放

videoview正常播放完毕会退出,如果做到循环播放,像朋友圈小视频一样?也是非常简单的。

       //循环播放
        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                proxyUrl = proxy.getProxyUrl(playUrl);
                videoView.setVideoPath(proxyUrl);
                videoView.start();
            }
        });

隐藏播放条

去掉 private MediaController mc; 屏蔽关于它的操作


交互,点击屏幕退出播放

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction()== MotionEvent.ACTION_UP){
            finish();
        }
        return true;
    }

解决横屏生命周期重新加载, 视频从头播放的问题

在默认情况下当萤幕从竖屏变到横屏时会触发onConfigurationChanged事件,画面会重新载入

解决:

  • a. 在manifest中设置该Activity的configChanges为
    android:configChanges=“screenSize|keyboardHidden|orientation”
  • b.重载onConfigurationChanged事件

解释:

  • a.不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
  • b.设置Activity的android:configChanges=“orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
  • c.设置Activity的android:configChanges=“orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
  • d.是由于google在android3.2中添加了screensize改变的通知,在转屏的时候,不仅是orientation发生了改变,screensize同样也发生了改变,所以要设置screenSize参数:
      只竖屏显示的话(android:screenOrientation="portrait")
      只横屏显示的话(android:screenOrientation="landscape")

加载时进度条的显示与消失 progressbar

视频最初加载的时候,如果什么处理都不做,网速又卡一点的话,会有几秒的黑屏,所以我们总要在加载的时候做一点处理,增加用户体验吧:可以直接放一个progressbar,或是生动一点,我是自定义了一个view,一个封面图加一个progressbar,加载的时候显示,加载完最初的一段就可以取消了。


1
     videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(MediaPlayer mp, int what, int extra) {
               if (what==MediaPlayer.MEDIA_INFO_BUFFERING_START){
                   bufferingCoverView.setVisibility(View.VISIBLE);
               }
               else {
                   bufferingCoverView.setVisibility(View.GONE);
               }
               return true;
            }
        });
        //在视频预处理完成后调用
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                bufferingCoverView.setVisibility(View.GONE);
            }
        });

把之前写类似朋友圈播放视频时遇到的问题总结出来,哈哈哈,给个赞鼓励一下吧~~比心❤️

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,401评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,702评论 22 664
  • 当高考真正结束,我的内心连死水微澜都不再有的时候,原来我已经不太在意高考了,当初刚进高中大门时怀揣的梦想...
    菅mang阅读 129评论 0 1
  • 提前跟自己说好,不管结果如何,都要勇敢地面对!勇敢的力量来自于对一切的包容与宠爱。做一个有爱的女孩子,不因世界对你...
    天心_7cda阅读 155评论 0 1
  • 今天痛痛快快的哭了一場,屁大點事情,讓我看到了性格模式的可怕! 不就是犯錯誤嗎?不做怎麽知道自己不對呢?因為...
    粟莎阅读 402评论 0 0