Browse Source

优化视频销毁时的优化逻辑

yangchong211 6 years ago
parent
commit
5d3f17bdf1

+ 1 - 1
.idea/misc.xml

@@ -29,7 +29,7 @@
       </value>
     </option>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/build/classes" />
   </component>
   <component name="ProjectType">

+ 2 - 1
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/controller/VideoPlayerController.java

@@ -254,7 +254,8 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
      * 初始化操作
      */
     private void init() {
-        LayoutInflater.from(mContext).inflate(R.layout.custom_video_player, this, true);
+        LayoutInflater.from(mContext).inflate(R.layout.custom_video_player,
+                this, true);
         initFindViewById();
         initListener();
         registerNetChangedReceiver();

+ 16 - 8
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/manager/VideoPlayerManager.java

@@ -10,13 +10,13 @@ import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
  *     blog  : https://github.com/yangchong211
  *     time  : 2017/10/21
  *     desc  : 视频播放器管理器
- *     revise:
+ *     revise: 将类置成final
  * </pre>
  */
 public final class VideoPlayerManager {
 
     private VideoPlayer mVideoPlayer;
-    private static VideoPlayerManager sInstance;
+    private static volatile VideoPlayerManager sInstance;
     private VideoPlayerManager() {}
 
     /**
@@ -24,9 +24,13 @@ public final class VideoPlayerManager {
      * 单例模式
      * @return          VideoPlayerManager对象
      */
-    public static synchronized VideoPlayerManager instance() {
+    public static VideoPlayerManager instance() {
         if (sInstance == null) {
-            sInstance = new VideoPlayerManager();
+            synchronized (VideoPlayerManager.class){
+                if (sInstance == null){
+                    sInstance = new VideoPlayerManager();
+                }
+            }
         }
         return sInstance;
     }
@@ -57,8 +61,10 @@ public final class VideoPlayerManager {
      * 当视频正在播放或者正在缓冲时,调用该方法暂停视频
      */
     public void suspendVideoPlayer() {
-        if (mVideoPlayer != null && (mVideoPlayer.isPlaying() || mVideoPlayer.isBufferingPlaying())) {
-            mVideoPlayer.pause();
+        if (mVideoPlayer != null) {
+            if (mVideoPlayer.isPlaying() || mVideoPlayer.isBufferingPlaying()){
+                mVideoPlayer.pause();
+            }
         }
     }
 
@@ -67,8 +73,10 @@ public final class VideoPlayerManager {
      * 当视频暂停时或者缓冲暂停时,调用该方法重新开启视频播放
      */
     public void resumeVideoPlayer() {
-        if (mVideoPlayer != null && (mVideoPlayer.isPaused() || mVideoPlayer.isBufferingPaused())) {
-            mVideoPlayer.restart();
+        if (mVideoPlayer != null) {
+            if (mVideoPlayer.isPaused() || mVideoPlayer.isBufferingPaused()){
+                mVideoPlayer.restart();
+            }
         }
     }
 

+ 54 - 30
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/player/VideoPlayer.java

@@ -1,6 +1,5 @@
 package org.yczbj.ycvideoplayerlib.player;
 
-import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.Color;
@@ -124,6 +123,23 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         return super.onKeyDown(keyCode, event);
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        VideoLogUtil.d("onAttachedToWindow");
+        //init();
+        //在构造函数初始化时addView
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        VideoLogUtil.d("onDetachedFromWindow");
+        //onDetachedFromWindow方法是在Activity destroy的时候被调用的,也就是act对应的window被删除的时候,
+        //且每个view只会被调用一次,父view的调用在后,也不论view的visibility状态都会被调用,适合做最后的清理操作
+        //防止开发者没有在onDestroy中没有做销毁视频的优化
+        release();
+    }
 
     /*--------------setUp为必须设置的方法,二选其一--------------------------------------*/
     /**
@@ -194,7 +210,10 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         }
         if (mMediaPlayer instanceof IjkMediaPlayer) {
             ((IjkMediaPlayer) mMediaPlayer).setSpeed(speed);
-        } else if(mMediaPlayer instanceof MediaPlayer){
+        } else if (mMediaPlayer instanceof AndroidMediaPlayer){
+            //((AndroidMediaPlayer) mMediaPlayer).setSpeed(speed);
+            VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
+        }else if(mMediaPlayer instanceof MediaPlayer){
             //((MediaPlayer) mMediaPlayer).setSpeed(speed);
             VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
         } else {
@@ -523,7 +542,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
 
     /**
      * 获取当前播放模式
-     * @return
+     * @return                  返回当前播放模式
      */
     public int getCurrentState(){
         return mCurrentState;
@@ -537,7 +556,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         if (mAudioManager == null) {
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             if (mAudioManager != null) {
-                mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+                mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+                        AudioManager.AUDIOFOCUS_GAIN);
             }
         }
     }
@@ -568,52 +588,53 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     private void createIjkMediaPlayer() {
         //创建IjkMediaPlayer对象
         mMediaPlayer = new IjkMediaPlayer();
-        int PLAYER = IjkMediaPlayer.OPT_CATEGORY_PLAYER;
-        int CODEC = IjkMediaPlayer.OPT_CATEGORY_CODEC;
-        int FORMAT = IjkMediaPlayer.OPT_CATEGORY_FORMAT;
+        int player = IjkMediaPlayer.OPT_CATEGORY_PLAYER;
+        int codec = IjkMediaPlayer.OPT_CATEGORY_CODEC;
+        int format = IjkMediaPlayer.OPT_CATEGORY_FORMAT;
 
         //设置ijkPlayer播放器的硬件解码相关参数
         //设置播放前的最大探测时间
-        ((IjkMediaPlayer)mMediaPlayer).setOption(FORMAT, "analyzemaxduration", 100L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzemaxduration", 100L);
         //设置播放前的探测时间 1,达到首屏秒开效果
-        ((IjkMediaPlayer)mMediaPlayer).setOption(FORMAT, "analyzeduration", 1L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "analyzeduration", 1L);
         //播放前的探测Size,默认是1M, 改小一点会出画面更快
-        ((IjkMediaPlayer)mMediaPlayer).setOption(FORMAT, "probesize", 10240L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "probesize", 10240L);
         //设置是否开启变调isModifyTone?0:1
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER,"soundtouch",0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player,"soundtouch",0);
         //每处理一个packet之后刷新io上下文
-        ((IjkMediaPlayer)mMediaPlayer).setOption(FORMAT, "flush_packets", 1L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "flush_packets", 1L);
         //是否开启预缓冲,一般直播项目会开启,达到秒开的效果,不过带来了播放丢帧卡顿的体验
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "packet-buffering", 0L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "packet-buffering", 0L);
         //播放重连次数
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "reconnect", 5);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "reconnect", 5);
         //最大缓冲大小,单位kb
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "max-buffer-size", 10240L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-buffer-size", 10240L);
         //跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "framedrop", 1L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1L);
         //最大fps
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "max-fps", 30L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "max-fps", 30L);
         //SeekTo设置优化
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "enable-accurate-seek", 1L);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "opensles", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "framedrop", 1);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "start-on-prepared", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(FORMAT, "http-detect-range-support", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "enable-accurate-seek", 1L);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "opensles", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "framedrop", 1);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "start-on-prepared", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(format, "http-detect-range-support", 0);
         //设置是否开启环路过滤: 0开启,画面质量高,解码开销大,48关闭,画面质量差点,解码开销小
-        ((IjkMediaPlayer)mMediaPlayer).setOption(CODEC, "skip_loop_filter", 48);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(codec, "skip_loop_filter", 48);
 
         //jkPlayer支持硬解码和软解码。
         //软解码时不会旋转视频角度这时需要你通过onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED去获取角度,自己旋转画面。
         //或者开启硬解硬解码,不过硬解码容易造成黑屏无声(硬件兼容问题),下面是设置硬解码相关的代码
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "mediacodec", 0);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "mediacodec-auto-rotate", 1);
-        ((IjkMediaPlayer)mMediaPlayer).setOption(PLAYER, "mediacodec-handle-resolution-change", 1);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec", 0);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-auto-rotate", 1);
+        ((IjkMediaPlayer)mMediaPlayer).setOption(player, "mediacodec-handle-resolution-change", 1);
     }
 
 
     /**
      * 初始化TextureView
+     * 这个主要是用作视频的
      */
     @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     private void initTextureView() {
@@ -936,7 +957,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     /**
      * 退出全屏模式
      * 退出全屏,移除mTextureView和mController,并添加到非全屏的容器中。
-     * 切换竖屏时需要在manifest的activity标签下添加android:configChanges="orientation|keyboardHidden|screenSize"配置,
+     * 切换竖屏时需要在manifest的activity标签下添加
+     * android:configChanges="orientation|keyboardHidden|screenSize"配置,
      * 以避免Activity重新走生命周期.
      *
      * @return true退出全屏.
@@ -1067,8 +1089,10 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             mMediaPlayer.release();
             mMediaPlayer = null;
         }
-        //从视图中移除TextureView
-        mContainer.removeView(mTextureView);
+        if (mContainer!=null){
+            //从视图中移除TextureView
+            mContainer.removeView(mTextureView);
+        }
         if (mSurface != null) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                 mSurface.release();

+ 19 - 5
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/utils/VideoPlayerUtils.java

@@ -28,7 +28,7 @@ import java.util.Locale;
 public final class VideoPlayerUtils {
 
     /**
-     * Get activity from context object
+     * 通过上下文获取到activity,使用到了递归
      *
      * @param context       上下文
      * @return              对象的活动对象,如果它不是活动对象,则为空。
@@ -145,7 +145,11 @@ public final class VideoPlayerUtils {
      * @param url               视频链接url
      */
     public static void savePlayPosition(Context context, String url, long position) {
-        context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION", Context.MODE_PRIVATE).edit().putLong(url, position).apply();
+        if (context==null){
+            return;
+        }
+        context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION",
+                Context.MODE_PRIVATE).edit().putLong(url, position).apply();
     }
 
     /**
@@ -155,7 +159,11 @@ public final class VideoPlayerUtils {
      * @return 上次保存的播放位置
      */
     public static long getSavedPlayPosition(Context context, String url) {
-        return context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION", Context.MODE_PRIVATE).getLong(url, 0);
+        if (context==null){
+            return 0;
+        }
+        return context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION",
+                Context.MODE_PRIVATE).getLong(url, 0);
     }
 
     /**
@@ -163,7 +171,11 @@ public final class VideoPlayerUtils {
      * @param context           上下文
      */
     public static void clearPlayPosition(Context context){
-        context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION", Context.MODE_PRIVATE).getAll().clear();
+        if (context==null){
+            return;
+        }
+        context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION",
+                Context.MODE_PRIVATE).getAll().clear();
     }
 
 
@@ -191,7 +203,9 @@ public final class VideoPlayerUtils {
     private static NetworkInfo getActiveNetworkInfo(Context context) {
         ConnectivityManager manager = (ConnectivityManager)
                 context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
-        if (manager == null) return null;
+        if (manager == null) {
+            return null;
+        }
         return manager.getActiveNetworkInfo();
     }
 

+ 5 - 1
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/view/VideoTextureView.java

@@ -56,7 +56,9 @@ public class VideoTextureView extends TextureView {
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         float viewRotation = getRotation();
         // 如果判断成立,则说明显示的TextureView和本身的位置是有90度的旋转的,所以需要交换宽高参数。
-        if (viewRotation == 90f || viewRotation == 270f) {
+        float viewRotation1 = 90f;
+        float viewRotation2 = 270f;
+        if (viewRotation == viewRotation1 || viewRotation == viewRotation2) {
             int tempMeasureSpec = widthMeasureSpec;
             //noinspection SuspiciousNameCombination
             widthMeasureSpec = heightMeasureSpec;
@@ -120,4 +122,6 @@ public class VideoTextureView extends TextureView {
         }
         setMeasuredDimension(width, height);
     }
+
+
 }

+ 12 - 0
read/wiki1.md

@@ -1,4 +1,16 @@
 # 基础方法说明
+#### 目录介绍
+- 01.最简单的播放
+- 02.竖屏全屏播放
+- 03.横屏全屏播放
+- 04.小窗口播放
+- 05.全屏播放切换视频清晰度
+- 06.在列表中播放
+- 07.在activity播放视频处理home键逻辑
+- 08.在fragment中播放
+- 09.显示视频top[分享,下载,更多按钮控件]
+- 10.全局悬浮播放视频
+- 11.常见api说明
 
 
 

+ 97 - 2
read/wiki2.md

@@ -9,7 +9,90 @@
 - 07.关于so库优化
 - 08.关于网络状态监听优化
 - 09.关于代码规范优化
-
+- 10.关于布局优化
+
+
+
+### 02.前后台切换优化
+#### 2.1 第一种优化方式
+- 从前台切到后台,当视频正在播放或者正在缓冲时,暂停视频;当从后台切换到前台,当视频暂停时或者缓冲暂停时,自动开启视频播放。比如常见优酷,爱奇艺就类似这样。
+    - **如果是在Activity中的话,建议设置下面这段代码**
+        ```
+        @Override
+        protected void onStop() {
+            super.onStop();
+            //从前台切到后台,当视频正在播放或者正在缓冲时,调用该方法暂停视频
+            VideoPlayerManager.instance().suspendVideoPlayer();
+        }
+
+        @Override
+        protected void onDestroy() {
+            super.onDestroy();
+            //销毁页面,释放,内部的播放器被释放掉,同时如果在全屏、小窗口模式下都会退出
+            VideoPlayerManager.instance().releaseVideoPlayer();
+        }
+
+        @Override
+        public void onBackPressed() {
+            //处理返回键逻辑;如果是全屏,则退出全屏;如果是小窗口,则退出小窗口
+            if (VideoPlayerManager.instance().onBackPressed()){
+                return;
+            }else {
+                //销毁页面
+                VideoPlayerManager.instance().releaseVideoPlayer();
+            }
+            super.onBackPressed();
+        }
+
+        @Override
+        protected void onRestart() {
+            super.onRestart();
+            //从后台切换到前台,当视频暂停时或者缓冲暂停时,调用该方法重新开启视频播放
+            VideoPlayerManager.instance().resumeVideoPlayer();
+        }
+        ```
+
+
+#### 2.2 第二种优化方式
+- 当视频播放时,切换后台页面处于不可见时,则销毁视频资源。从后台切换到前台时,用户需要手动触发点击才能继续看视频。
+    - **如果是在Activity中的话,建议设置下面这段代码**
+        ```
+        @Override
+        protected void onStop() {
+            super.onStop();
+            VideoPlayerManager.instance().releaseVideoPlayer();
+        }
+
+        @Override
+        public void onBackPressed() {
+            if (VideoPlayerManager.instance().onBackPressed()) return;
+            super.onBackPressed();
+        }
+        ```
+    - **如果是在Fragment中的话,建议设置下面这段代码**
+        ```
+        //在宿主Activity中设置代码如下
+        @Override
+        protected void onStop() {
+            super.onStop();
+            VideoPlayerManager.instance().releaseVideoPlayer();
+        }
+
+        @Override
+        public void onBackPressed() {
+            if (VideoPlayerManager.instance().onBackPressed()) return;
+            super.onBackPressed();
+        }
+
+        //--------------------------------------------------
+
+        //在此Fragment中设置代码如下
+        @Override
+        public void onStop() {
+            super.onStop();
+            VideoPlayerManager.instance().releaseVideoPlayer();
+        }
+        ```
 
 
 
@@ -84,7 +167,19 @@
 
 
 
-
+### 10.关于布局优化
+- 关于正式项目中视频可能存在的布局
+    - 视频播放器初始化状态布局
+    - 视频播放加载状态布局
+    - 视频播放器顶部布局[返回键,分享键,下载键,更多键,或者其他控件]
+    - 视频播放器底部布局[播放,暂停按钮,视频进度条,切换全屏控件]
+    - 视频试看模式状态布局
+    - 视频试看结束后状态布局
+    - 视频观看结束后状态布局
+    - 音视频之间切换效果[状态]
+    - 视频播放错误时状态布局
+    - 会员权限等布局,非会员时显示布局
+    - 全屏播放时的布局