admin 发表于 2016-11-28 11:47:47

Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPla...

Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPlayer)<p></p><div><br></div><div><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">Android 实现视屏播放器与边播边缓存功能外加蹲坑铲屎(IJKPlayer)</p><h5 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 18px;"> hello,大家好,我就是那个会掀桌子的话唠,刚刚结束两篇关于音频播放与录制的文章,旧坑未埋就挖新坑,还望多多关照。最近累趴了,周末果断休假。</h5><h6 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 16px;">快看,用力戳它:<a href="https://github.com/CarGuo/GSYVideoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">https://github.com/CarGuo/GSYVideoPlayer</a>&nbsp;。项目是翻改至<a href="https://github.com/lipangit/JieCaoVideoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">JieCaoVideoPlayer</a>,本文特长,看官请耐心,妹子会有的。</h6><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">效果<br></p><div class="image-package imagebubble" widget="ImageBubble" style="margin-right: auto; margin-bottom: 20px; margin-left: auto; text-align: center; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><img src="http://upload-images.jianshu.io/upload_images/3673902-e3d20b0625ddce1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" data-original-src="http://upload-images.jianshu.io/upload_images/3673902-e3d20b0625ddce1b.png?imageMogr2/auto-orient/strip%7CimageView2/2" class="imagebubble-image" style="max-width: 100%; height: auto; vertical-align: middle; border: 0px; cursor: -webkit-zoom-in; transition: all 0.25s ease-in-out; opacity: 1;"><br></div><h3 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 22px;">开源播放器选择</h3><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> Android上最为人熟知的<strong>MediaPlayer</strong>,对,就是这货,在上两篇音频文章中频频露脸的家伙,这次又有它的身影,然而还是这次不讲他,就连他的封装类VideoView也不讲&lt;( ̄︶ ̄)&gt;,呸呸呸,又扯了一堆没用的。</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;"><a href="https://github.com/Bilibili/ijkplayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">ijkplayer</a>,这次要推荐的是它,鼎鼎大名的<strong>BILIBILI</strong>开源的播放器。基于<strong>FFMPEG</strong>,支持Android与IOS,还封装了谷歌亲儿子<strong>MediaPlayer</strong>与干儿子<a href="https://github.com/google/ExoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">EXOPlayer</a>(为什么要用EXO),支持直播流,Star-9000多与fork-3000的视频播放器你支持安利。(issues 600多算活跃吗┑( ̄Д  ̄)┍)</li></ul><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 集成工作还是有定的工作量的,它的DEMO肯定满足不了欲求不满的设计狮和产品汪的,这里我们不跑分,不打广告,不讲原理,只求站在巨人的肩膀上学(cao)习(xi),快速集成。</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">定义一个单例的视频内核播放管理器。</li><li style="line-height: 30px;">自定义一个满足你上下其手的TextureView</li><li style="line-height: 30px;">定义一个UI层级逻辑播放器</li><li style="line-height: 30px;">重力旋转的相关逻辑处理</li><li style="line-height: 30px;">列表逻辑的相关处理</li><li style="line-height: 30px;">列表到全屏相关的逻辑处理</li><li style="line-height: 30px;">视频缓存逻辑</li></ul><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">1、播放管理器:GSYVideoManager</h4><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 单例,没得商量,它需要负责真正的播放请求与显示逻辑,集成了<strong>IjkMediaPlayer</strong>,BILIBLI的开源小组还是很有心的,它的封装和接口使用基本和MediaPlayer没有什么区别,只需要用起来就好了。‘</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 这里我们要实现<strong>IjkMediaPlayer</strong>的播放接口,监听<strong>IjkMediaPlayer</strong>的相关状态回调然后封发到各个逻辑播放器中。从下方代码可以看到,真的和MediaPlayer好像。</p><pre class="hljs scala" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="scala" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">mediaPlayer = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> <span class="hljs-type" style="color: rgb(181, 137, 0);">IjkMediaPlayer</span>();
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//音频类型</span>
mediaPlayer.setAudioStreamType(<span class="hljs-type" style="color: rgb(181, 137, 0);">AudioManager</span>.<span class="hljs-type" style="color: rgb(181, 137, 0);">STREAM_MUSIC</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//数据源</span>
mediaPlayer.setDataSource(((<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYModel</span>) msg.obj).getUrl(), ((<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYModel</span>) msg.obj).getMapHeadData());
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//播放完成</span>
mediaPlayer.setOnCompletionListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//缓冲</span>
mediaPlayer.setOnBufferingUpdateListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//常亮</span>
mediaPlayer.setScreenOnWhilePlaying(<span class="hljs-literal">true</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//加载完毕</span>
mediaPlayer.setOnPreparedListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//拖动</span>
mediaPlayer.setOnSeekCompleteListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//失败</span>
mediaPlayer.setOnErrorListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//视频相关信息-重要</span>
mediaPlayer.setOnInfoListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//视频大小</span>
mediaPlayer.setOnVideoSizeChangedListener(<span class="hljs-type" style="color: rgb(181, 137, 0);">GSYVideoManager</span>.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);】
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//开始加载</span>
mediaPlayer.prepareAsync();</code></pre><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 监听的回调接口里,大部分大家都耳目能详吧,没听过也没关系,都写上就对了,但是最主要需要关注的两个,一个是通过<strong>setOnVideoSizeChangedListener</strong>拿到视频宽和高,这是我们后续正常显示视频的依靠之一。</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 另外一个就是<strong>setOnInfoListener</strong>,这里我们主要是获取到视频相关的元信息里视频<strong>旋转角度</strong>!还记得那时候对视频播放不熟悉,和产品还有QA力争“这个视频本来就是转了90度的,我就不改,你咬我吗···”这样的黑历史。<strong>Σ( ° △ °|||)</strong></p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> <strong>特别是Android拍摄的竖屏视频,旋转不是视频本身的图像,而是增加了旋转信息,而这个时候你需要做的就是识别它,然后转了它丫的。另外,因为Android本身的MediaPlaer和VideoView自身就处理好所以不需要你旋转。</strong>((ノO益O)ノ彡┻━┻亲生的啊)</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 这里的接口主要是把当前播放的视频状态和信息到返回到逻辑播放器中。</p><pre class="hljs java" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-annotation">@Override</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">onInfo</span><span class="hljs-params">(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> what, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> extra)</span> </span>{
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
      BACKUP_PLAYING_BUFFERING_STATE = mCurrentState;
      setStateAndUi(CURRENT_STATE_PLAYING_BUFFERING_START);
    } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (BACKUP_PLAYING_BUFFERING_STATE != -<span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>) {
            setStateAndUi(BACKUP_PLAYING_BUFFERING_STATE);
            BACKUP_PLAYING_BUFFERING_STATE = -<span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>;
      }
    } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//这里返回了视频旋转的角度,根据角度旋转视频到正确的画面</span>
      mRotate = extra;
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mTextureView != <span class="hljs-keyword" style="color: rgb(133, 153, 0);">null</span>)
            mTextureView.setRotation(mRotate);
    }
}</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">2、自定义TextureView:GSYTextureView</h4><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 为什么不用SurfaceView?因为TextureView很可爱啊。这里我们主要针对视频的大小和旋转角度设置TextureView的大小,详细就不多说了(不是懒),挑其中一类讲讲,因为主要也是这个。</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">例如根据视频的长宽比和屏幕的长宽比判断,如果视频宽与屏幕宽之比小于高之比,那么就需要按理比压缩宽度,然后高度适应屏幕。  </li><li style="line-height: 30px;">例如根据旋转信息,判断TextureView界面的比例是横的还是竖的,如果View是竖的,而视频也是竖的,那么因为旋转了90度,那么让视频的高显示为屏幕的宽度,从新计算旋转后的宽度。</li></ul><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">觉得看起来有点绕口?没关系,用着用着就习惯了····</p><pre class="hljs cpp" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="cpp" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">width = widthSpecSize;
height = heightSpecSize;
···
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (videoWidth * height &lt; width * videoHeight) {
    width = height * videoWidth / videoHeight;
} <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (videoWidth * height &gt; width * videoHeight) {
    height = width * videoHeight / videoWidth;
}
···
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (getRotation() != <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span> &amp;&amp; getRotation() % <span class="hljs-number" style="color: rgb(42, 161, 152);">90</span> == <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) {
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (widthS &lt; heightS) {
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (width &gt; height) {
            width = (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span>) (width * (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span>) widthS / height);
            height = widthS;
      } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
            height = (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span>) (height * (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span>) width / widthS);
            width = widthS;
      }
    } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (width &gt; height) {
            height = (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span>) (height * (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span>) width / widthS);
            width = widthS;
      } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
            width = (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span>) (width * (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span>) widthS / height);
            height = widthS;
      }
    }
}</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">3、UI层级逻辑播放器 GSYVideoPlayer</h4><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 所有的UI逻辑基本都可以写到这里,目前继承了 FrameLayout,View.OnClickListener, View.OnTouchListener, SeekBar.OnSeekBarChangeListener, TextureView.SurfaceTextureListener和GSYMediaPlayerListener。<br> <br> 逻辑播放器实现的内容太多了,这里主要说几个地方,好吧,我承认我懒╮(╯_╰)╭ ,但是写太多了也没人看啊,所以这里主要是说一些关键的点,有需要留言再开个坑聊一聊,反正有DEMO。</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">记录界面的播放状态,把播放管理器GSYVideoManager的状态记录下来,如果有别的逻辑播放器点击播放了,就把原本的逻辑播放器状态清空,所有逻辑播放器的整个界面的UI都是根据这个<strong>State</strong>来决定的。</li></ul><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 在逻辑播放器中统一分发各种状态,把被播放的manager状态同步到这里,之后你想要在哪个逻辑播放器里播放只需要对应的设置状态后把manager的监听同步过来。</p><pre class="hljs objectivec" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="objectivec" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">switch</span> (mCurrentState) {
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//正常初始化状态</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_NORMAL:
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (isCurrentMediaListener()) {
            cancelProgressTimer();
            GSYVideoManager<span class="hljs-variable" style="color: rgb(181, 137, 0);">.instance</span>()<span class="hljs-variable" style="color: rgb(181, 137, 0);">.releaseMediaPlayer</span>();
      }
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;

    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//loading中</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_PREPAREING:
      resetProgressAndTime();
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//播放中</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_PLAYING:
      startProgressTimer();
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//暂停</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_PAUSE:
      startProgressTimer();
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//错误-需要判断是否切换了逻辑播放器</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_ERROR:
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (isCurrentMediaListener()) {
            GSYVideoManager<span class="hljs-variable" style="color: rgb(181, 137, 0);">.instance</span>()<span class="hljs-variable" style="color: rgb(181, 137, 0);">.releaseMediaPlayer</span>();
      }
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//结束</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> CURRENT_STATE_AUTO_CO<span class="hljs-built_in" style="color: rgb(38, 139, 210);">MPLETE</span>:
      cancelProgressTimer();
      mProgressBar<span class="hljs-variable" style="color: rgb(181, 137, 0);">.setProgress</span>(<span class="hljs-number" style="color: rgb(42, 161, 152);">100</span>);
      mCurrentTimeTextView<span class="hljs-variable" style="color: rgb(181, 137, 0);">.setText</span>(mTotalTimeTextView<span class="hljs-variable" style="color: rgb(181, 137, 0);">.getText</span>());
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">break</span>;
}</code></pre><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">增加界面的<strong>onTouch</strong>事件,根据<strong>View</strong>的<strong>getId</strong>判断触摸的是进度条还是界面,如果是界面判断是左右滑动就显示<strong>Dialog</strong>并<strong>seekTo</strong>,如果是上下就根据屏幕的左边还是右边来选择是调节<strong>音量</strong>还是<strong>亮度</strong>。</li></ul><pre class="hljs cpp" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="cpp" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">···
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">case</span> MotionEvent.ACTION_MOVE:
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span> deltaX = x - mDownX;
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span> deltaY = y - mDownY;
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span> absDeltaX = Math.<span class="hljs-built_in" style="color: rgb(38, 139, 210);">abs</span>(deltaX);
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">float</span> absDeltaY = Math.<span class="hljs-built_in" style="color: rgb(38, 139, 210);">abs</span>(deltaY);
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//是全屏还是设置了可以触摸</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mIfCurrentIsFullscreen || mIsTouchWiget) {
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//之前是否已经符合了触摸逻辑条件</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!mChangePosition &amp;&amp; !mChangeVolume &amp;&amp; !mBrightness) {
            <span class="hljs-comment" style="color: rgb(147, 161, 161);">//如果手指动了超过一定距离就可以判断是滑动,防止点击的误判的</span>
            <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (absDeltaX &gt; mThreshold || absDeltaY &gt; mThreshold) {
                cancelProgressTimer();
                <span class="hljs-comment" style="color: rgb(147, 161, 161);">//如果是左右的就是进度</span>
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (absDeltaX &gt;= mThreshold) {
                  mChangePosition = <span class="hljs-literal">true</span>;
                  mDownPosition = getCurrentPositionWhenPlaying();
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mVideoAllCallBack != <span class="hljs-function">null &amp;&amp; <span class="hljs-title" style="color: rgb(38, 139, 210);">isCurrentMediaListener</span><span class="hljs-params">()</span>) </span>{
                        mVideoAllCallBack.onTouchScreenSeekPosition(mUrl, mObjects);
                  }
                } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {

                <span class="hljs-comment" style="color: rgb(147, 161, 161);">//如果是上下的判断是左边还是右边</span>
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mFirstTouch) {
                        mBrightness = mDownX &lt; mScreenWidth * <span class="hljs-number" style="color: rgb(42, 161, 152);">0.5f</span>;
                        mFirstTouch = <span class="hljs-literal">false</span>;
                  }
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!mBrightness) {
                        mChangeVolume = <span class="hljs-literal">true</span>;
                        mGestureDownVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                        <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mVideoAllCallBack != <span class="hljs-function">null &amp;&amp; <span class="hljs-title" style="color: rgb(38, 139, 210);">isCurrentMediaListener</span><span class="hljs-params">()</span>) </span>{
                            mVideoAllCallBack.onTouchScreenSeekVolume(mUrl, mObjects);
                        }
                  }
                }
            }
      }
    }
    ···
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//根据flag执行逻辑</span></code></pre><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">要监听<strong>TextureView.setSurfaceTextureListener</strong>来通知画面的创建和销毁,比如回到后台,onPause等。</li></ul><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">这里有一个是TextureView的动态添加,动态添加的好处是你可以在不停止视频的情况下载不同的逻辑播放器中切换视频播放,比如列表全屏。</p><pre class="hljs java" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">protected</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">addTextureView</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mTextureViewContainer.getChildCount() &gt; <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) {
      mTextureViewContainer.removeAllViews();
    }
    mTextureView = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">null</span>;
    mTextureView = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> GSYTextureView(getContext());
    mTextureView.setSurfaceTextureListener(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
    mTextureView.setRotation(mRotate);

    RelativeLayout.LayoutParams layoutParams = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
    mTextureViewContainer.addView(mTextureView, layoutParams);
}

···

<span class="hljs-comment" style="color: rgb(147, 161, 161);">//把Surface丢给视频播放管理</span>
<span class="hljs-annotation">@Override</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">onSurfaceTextureAvailable</span><span class="hljs-params">(SurfaceTexture surface, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> width, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> height)</span> </span>{
    mSurface = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> Surface(surface);
    GSYVideoManager.instance().setDisplay(mSurface);
}

<span class="hljs-comment" style="color: rgb(147, 161, 161);">//告诉视频播放渲染画面销毁了</span>
<span class="hljs-annotation">@Override</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">boolean</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">onSurfaceTextureDestroyed</span><span class="hljs-params">(SurfaceTexture surface)</span> </span>{
    GSYVideoManager.instance().setDisplay(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">null</span>);
    surface.release();
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">return</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">true</span>;
}</code></pre><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">每次播放都要把Manager的player的监听移到当前播放的逻辑播放器,这样才能够正确的监听视频的播放状态。</li></ul><pre class="hljs objectivec" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="objectivec" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-comment" style="color: rgb(147, 161, 161);">//这里其实就有播放管理器的监听分发保存的逻辑需要注意</span>
GSYVideoManager<span class="hljs-variable" style="color: rgb(181, 137, 0);">.instance</span>()<span class="hljs-variable" style="color: rgb(181, 137, 0);">.setLastListener</span>(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
GSYVideoManager<span class="hljs-variable" style="color: rgb(181, 137, 0);">.instance</span>()<span class="hljs-variable" style="color: rgb(181, 137, 0);">.setListener</span>(gsyVideoPlayer);</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">3、列表全屏逻辑 :Window层级的全屏、单例逻辑播放器的全屏ListVideoUtil。</h4><br style="color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><span style="color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">效果GIF(比较大):</span><div class="image-package imagebubble" widget="ImageBubble" style="margin-right: auto; margin-bottom: 20px; margin-left: auto; text-align: center; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><img src="http://upload-images.jianshu.io/upload_images/3673902-faca46b0c90feaeb.gif?imageMogr2/auto-orient/strip" data-original-src="http://upload-images.jianshu.io/upload_images/3673902-faca46b0c90feaeb.gif?imageMogr2/auto-orient/strip" class="imagebubble-image" style="max-width: 100%; height: auto; vertical-align: middle; border: 0px; cursor: -webkit-zoom-in; transition: all 0.25s ease-in-out;"><br></div><h5 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 18px;">1)、Window层级的</h5><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> <br> 传闻每一个Activity都有一个<strong>com.android.internal.R.id.content</strong>,它默默的包含了各种你塞进去的物体,而且是一个<strong>FrameLayout</strong>,谷歌有太多它的传说了,我们用它是就是。</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 既然是<strong>FrameLayout</strong>,那么我们往他里面塞东西就好了,这里我们可以在<strong>GSYVideoPlayer</strong>里面写一个方法,在点击全屏按钮的时候:</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">隐藏状态栏,清除当前TextureView。</li><li style="line-height: 30px;">然后新创建一个<strong>GSYVideoPlayer2</strong>,只有把这个<strong>G2</strong>添加到window下<strong>FrameLayout</strong>。</li><li style="line-height: 30px;">设置它的播放状态和当前列表这个逻辑播放器一致。</li><li style="line-height: 30px;">最后把G2告知Manager承接画面,这样是就实现了无缝的列表到全屏啦,返回只需要倒着做就好了。</li></ul><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> <br> 在切换的时候可以做一些位移动画,让播放器的全屏更加友好,下面长代码来袭((/- -)/。深夜码字不易,不知道为什么每次这个时候老婆的意见很大啊。</p><pre class="hljs cpp" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="cpp" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">Constructor&lt;GSYBaseVideoPlayer&gt; constructor = (Constructor&lt;GSYBaseVideoPlayer&gt;) GSYBaseVideoPlayer.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>.getClass().getConstructor(Context.<span class="hljs-keyword" style="color: rgb(133, 153, 0);">class</span>);
final GSYBaseVideoPlayer gsyVideoPlayer = constructor.newInstance(getContext());
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//记录新创建的这个video的id,在返回的时候通过它销毁</span>
gsyVideoPlayer.setId(FULLSCREEN_ID);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
final <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> w = wm.getDefaultDisplay().getWidth();
final <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> h = wm.getDefaultDisplay().getHeight();
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//设置黑色背景,自动充满全屏</span>
FrameLayout.LayoutParams lpParent = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout frameLayout = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> FrameLayout(context);
frameLayout.setBackgroundColor(Color.BLACK);

<span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.LOLLIPOP) {
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//如果5.0的话,先让播放器出现的位置和列表中一直,再样式一会执行到屏幕中间的过度动画效果</span>
    FrameLayout.LayoutParams lp = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> FrameLayout.LayoutParams(getWidth(), getHeight());
    lp.setMargins(mListItemRect[<span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>], mListItemRect[<span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>], <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>, <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>);
    frameLayout.addView(gsyVideoPlayer, lp);
    vp.addView(frameLayout, lpParent);
    mHandler.postDelayed(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> Runnable() {
      @<span class="hljs-function">Override
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">run</span><span class="hljs-params">()</span> </span>{
            TransitionManager.beginDelayedTransition(vp);
            resolveFullVideoShow(context, gsyVideoPlayer, h, w);
      }
    }, <span class="hljs-number" style="color: rgb(42, 161, 152);">300</span>);
} <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//5.0一下直接显示</span>
    FrameLayout.LayoutParams lp = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> FrameLayout.LayoutParams(getWidth(), getHeight());
    frameLayout.addView(gsyVideoPlayer, lp);
    vp.addView(frameLayout, lpParent);
    resolveFullVideoShow(context, gsyVideoPlayer, h, w);
}
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//设置全屏逻辑播放器的状态,动态及添加播放view</span>
gsyVideoPlayer.setUp(mUrl, mCache, mObjects);
gsyVideoPlayer.setStateAndUi(mCurrentState);
gsyVideoPlayer.addTextureView();
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//添加监听</span>
GSYVideoManager.instance().setLastListener(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
GSYVideoManager.instance().setListener(gsyVideoPlayer);</code></pre><h5 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 18px;">2)、ListVideoUtil的单例模式</h5><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 这里利用另外一种实现思路,列表的逻辑播放器只用一个,因为普通的list在滑动的时候会有复用和销毁,这会导致视频被释放而停止了,如果你是和<strong>今日黄(tou)条</strong>一样的视频列表播放效果,滑出屏幕就停止那无所谓。</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 如果你需要无论怎么滑动,视频都在原来的位置播放的话,那么ListVideoUtil适合你,,内部它已经带了全屏,防错位,旋转的各种逻辑,直接上代码,有兴趣的看DEMO。</p><pre class="hljs java" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">listVideoUtil = <span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> ListVideoUtil(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">this</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//设置列表最外层的布局用于全屏,空FrameLayout</span>
listVideoUtil.setFullViewContainer(videoFullContainer);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//全屏隐藏状态栏,如果有的话</span>
listVideoUtil.setHideStatusBar(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">true</span>);

···
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//在列表中吧列表位置,封面,哪个列表的TAG,列表视频的承载ViewGroup,播放按键传入到Utils中</span>
listVideoUtil.addVideoPlayer(position, imageView, TAG, holder.videoContainer, holder.playerBtn);
holder.playerBtn.setOnClickListener(<span class="hljs-keyword" style="color: rgb(133, 153, 0);">new</span> View.OnClickListener() {
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">onClick</span><span class="hljs-params">(View v)</span> </span>{
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//每次播放都要更新列表让其他的item恢复状态</span>
      notifyDataSetChanged();
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//设置播放的tag和位置,防止错位</span>
      listVideoUtil.setPlayPositionAndTag(position, TAG);
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//开始播放</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">final</span> String url = <span class="hljs-string" style="color: rgb(42, 161, 152);">"http://baobab.wdjcdn.com/14564977406580.mp4"</span>;
      listVideoUtil.startPlay(url);
    }
});</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">4、OrientationUtils 重力旋转的工具类</h4><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><strong>OrientationUtils</strong>使用的是<strong>OrientationEventListener</strong>,通过手机的角度判断需要旋转到哪个位置。为什么用它?因为谷歌到的时候刚好看到,缘分啊懂吗。</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">这里需要个关注的是手动点击和自动旋转之间的冲突,主要看代码吧,老婆开始催我了 (ノಠ益ಠ)ノ彡┻━┻。</p><pre class="hljs cpp" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="cpp" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-comment" style="color: rgb(147, 161, 161);">//判断系统是否开了旋转,是的,这货不需要系统旋转是否开启</span>
boolean autoRotateOn = (android.provider.Settings.System.getInt(activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) == <span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>);
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!autoRotateOn) {
            <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mIsLand == <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) {
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">return</span>;
            }
      }
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">// 设置竖屏</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (((rotation &gt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) &amp;&amp; (rotation &lt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">30</span>)) || (rotation &gt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">330</span>)) {
            <span class="hljs-comment" style="color: rgb(147, 161, 161);">//是否点击导致的</span>
            <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mClick) {
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mIsLand &gt; <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span> &amp;&amp; !mClickLand) {
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">return</span>;
                } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
                  <span class="hljs-comment" style="color: rgb(147, 161, 161);">//清除状态</span>
                  mClickPort = <span class="hljs-literal">true</span>;
                  mClick = <span class="hljs-literal">false</span>;
                  mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>;
                }
            } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
                <span class="hljs-comment" style="color: rgb(147, 161, 161);">//自动旋转</span>
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mIsLand &gt; <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) {
                  screenType = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                  activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                  gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_enlarge);
                  mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>;
                  mClick = <span class="hljs-literal">false</span>;
                }
            }
      }
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">// 设置横屏</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (((rotation &gt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">230</span>) &amp;&amp; (rotation &lt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">310</span>))) {
            <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mClick) {
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!(mIsLand == <span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>) &amp;&amp; !mClickPort) {
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">return</span>;
                } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
                  mClickLand = <span class="hljs-literal">true</span>;
                  mClick = <span class="hljs-literal">false</span>;
                  mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>;
                }
            } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!(mIsLand == <span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>)) {
                  screenType = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                  activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                  gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_shrink);
                  mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">1</span>;
                  mClick = <span class="hljs-literal">false</span>;
                }
            }
      }
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">// 设置反向横屏</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (rotation &gt; <span class="hljs-number" style="color: rgb(42, 161, 152);">30</span> &amp;&amp; rotation &lt; <span class="hljs-number" style="color: rgb(42, 161, 152);">95</span>) {
            <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (mClick) {
                <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!(mIsLand == <span class="hljs-number" style="color: rgb(42, 161, 152);">2</span>) &amp;&amp; !mClickPort) {
                  <span class="hljs-keyword" style="color: rgb(133, 153, 0);">return</span>;
                } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> {
                  mClickLand = <span class="hljs-literal">true</span>;
                  mClick = <span class="hljs-literal">false</span>;
                  mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">2</span>;
                }
            } <span class="hljs-keyword" style="color: rgb(133, 153, 0);">else</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (!(mIsLand == <span class="hljs-number" style="color: rgb(42, 161, 152);">2</span>)) {
                screenType = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_shrink);
                mIsLand = <span class="hljs-number" style="color: rgb(42, 161, 152);">2</span>;
                mClick = <span class="hljs-literal">false</span>;
            }
      }
    }
};
orientationEventListener.enable();</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">6、边播边缓存</h4><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 好吧,老婆睡了,我偷偷起来了(。・・)ノ<br> 这个需求曾经让我彻夜难眠,因为IJKPlayer不支持,好吧,没见过哪个播放器支持的,和产品争(tuo)论(yan)需(shi)求(jian)之后,最终还是github大法好:<a href="https://github.com/danikula/AndroidVideoCache" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">AndroidVideoCache</a>。</p><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 接入简单,使用简单,你可以趾高气扬的和产品说,这个so easy了。</p><pre class="hljs javascript" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="javascript" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;">HttpProxyCacheServer proxy = getProxy();
<span class="hljs-comment" style="color: rgb(147, 161, 161);">//注意不能传入本地路径,本地的你还传进来干嘛。</span>
<span class="hljs-built_in" style="color: rgb(38, 139, 210);">String</span> proxyUrl = proxy.getProxyUrl(VIDEO_URL);
videoView.setVideoPath(proxyUrl);</code></pre><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> 该项目的原理其实就是将<strong>url链接转化为本地链接 h t t p://127.0.0.1:LocalPort/url</strong>,然后它开一个服务器一边下载缓存视频,一边把缓存的数据正常返回给你的播放器,如果已经缓存过的这里会返回一个本地文件路径。Σ( ° △ °|||)︴曾经的我真的是too young too smiple。</p><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">5、一些坑和说明</h4><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">1、IJKPLAY的后台播放和回到前台恢复画面的速度之快是其他播放器(我坐井观天)无法比拟的,真的好快,而且适合你,因为你什么都不用做。</p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">2、IJKPLAY有一个问题,我也提过ISSUSE了&nbsp;<a href="https://github.com/Bilibili/ijkplayer/issues/2104" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">#2104</a>,不过目前还未解决,就是某些短小的视频会无法seekTo,说是FFMEPG的问题,然后就太监了。</p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">3、IJKPLAY库里还封装了<strong>exoplayer</strong>谷歌干儿子,用法也基本一致,这个播放器自己内部判断旋转,不会有上面的seekto问题,可是后台或者onPause之后的画面恢复速度堪忧啊,各位遇到过吗?</p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">4、千万别开硬解码,不然会这样。 ( ‵o′)凸</p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">5、拖动进度条,需要在停止拖动的时候,判断视频是不是已经播放完了被释放了。</p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;">6、如果横屏全屏的话,恢复到正常画面是最好有一个延时,这样画面才不会出现背景抖动的问题,还有最关键的,<strong>Maifest</strong>文件。</p></li></ul><pre class="hljs objectivec" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="objectivec" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-comment" style="color: rgb(147, 161, 161);">//不要忘记配置activity,所有背景的activity</span>

android:configChanges=<span class="hljs-string" style="color: rgb(42, 161, 152);">"orientation|keyboardHidden|screenSize"</span></code></pre><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;">7、普通列表中播放视频在快速移动可能出现的错位问题</li></ul><pre class="hljs java" style="padding: 9.5px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; color: rgb(101, 123, 131); border-radius: 4px; margin-bottom: 20px; line-height: 20px; word-break: break-all; word-wrap: normal; border: 1px solid rgba(0, 0, 0, 0.14902); overflow: auto; background: rgb(253, 246, 227);"><code class="java" style="font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border-radius: 3px; border: none; background-color: transparent;"><span class="hljs-annotation">@Override</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">public</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">void</span> <span class="hljs-title" style="color: rgb(38, 139, 210);">onScroll</span><span class="hljs-params">(AbsListView view, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> firstVisibleItem, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> visibleItemCount, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> totalItemCount)</span> </span>{
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> lastVisibleItem = firstVisibleItem + visibleItemCount;
    <span class="hljs-comment" style="color: rgb(147, 161, 161);">//大于0说明有播放</span>
    <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (GSYVideoManager.instance().getPlayPosition() &gt;= <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>) {
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//当前播放的位置</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> position = GSYVideoManager.instance().getPlayPosition();
      <span class="hljs-comment" style="color: rgb(147, 161, 161);">//对应的播放列表TAG</span>
      <span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (GSYVideoManager.instance().getPlayTag().equals(ListNormalAdapter.TAG)
                &amp;&amp; (position &lt; firstVisibleItem || position &gt; lastVisibleItem)) {
            <span class="hljs-comment" style="color: rgb(147, 161, 161);">//如果滑出去了上面和下面就是否,和今日头条一样</span>
            GSYVideoPlayer.releaseAllVideos();
            listNormalAdapter.notifyDataSetChanged();
      }
    }
}</code></pre><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">到底了呢(^o^)/。</h4><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">下面的的看到了吗 ?&lt;( ̄︶ ̄)&gt;</h4><h4 style="font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 1.8; color: rgb(47, 47, 47); text-rendering: optimizeLegibility; font-size: 20px;">点我点我上60级:<a href="https://github.com/CarGuo/GSYVideoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">https://github.com/CarGuo/GSYVideoPlayer</a></h4><br style="color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><span style="color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;">能看到这里都是真爱啊,我最后问两句,你们会觉得文章太长阅读起来比较费劲吗?</span><p style="margin-bottom: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"> <br>相关文章:&nbsp;<a href="http://www.jianshu.com/p/bb5876f34902" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">Android 列表视频的全屏、自动小窗口优化实践</a><br> <br>友情链接:</p><ul style="margin-bottom: 20px; margin-left: 25px; text-align: justify; word-break: break-word; color: rgb(47, 47, 47); font-family: -apple-system, 'Helvetica Neue', Arial, 'PingFang SC', 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; font-size: 16px; line-height: 27.2px;"><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;"><a href="https://github.com/CarGuo/GSYVideoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">GSYVideoPlayer</a></p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;"><a href="https://github.com/Bilibili/ijkplayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">ijkplayer</a></p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;"><a href="https://github.com/danikula/AndroidVideoCache" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">AndroidVideoCache</a></p></li><li style="line-height: 30px;"><p style="margin-top: 16px; margin-bottom: 16px; word-break: break-word; overflow: visible;"><a href="https://github.com/lipangit/JieCaoVideoPlayer" target="_blank" style="color: rgb(64, 148, 199); text-decoration: none;">JieCaoVideoPlayer</a></p></li></ul></div>


原文地址:
http://www.jianshu.com/p/9fe377dd9750#
页: [1]
查看完整版本: Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPla...