悲剧!一个全局视频播放器引发的惨案

悲剧!一个全局视频播放器引发的惨案


案件描述

列表中、全屏可播放的视频播放器,实现:列表item提供父容器add播放器videoView,全屏用DecorView直接add播放器videoView

onDetachedFromWindow里清除播放器即从列表item父容器移除播放器videoView,并且videoView置为null

播放器在列表中播放视频,移出屏幕正常

播放器设置全屏播放,crash

onDetachedFromWindow方法

@Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (adBean == null || ListVideoPlayMg.getInstance().isDestroy()) {
            return;
        }
        // 非全屏清除播放器
        // 全屏时实现 是通过DecorView添加播放器,此时再调用cleanVideoView(1、remove后requestLayout,2、videoView = null)
        // DecorView.layoutChildren时导致child即videoView为null,导致NullPointerException
        if (!ListVideoPlayMg.getInstance().isFullScreen()) {
            ListVideoPlayMg.getInstance().cleanVideoView();
        }
    }
ListVideoPlayMg.getInstance().cleanVideoView();
/**
     * 清空播放器
     * Note:在item的的onDetachedFromWindow()方法中执行该方法时,要判断非全屏状态!
     */
    public void cleanVideoView() {
        stopFullScreen();
        if (mVideo != null) {
            if (mCurPlayerModel != null) {
                mProgressManager.saveProgress(mCurPlayerModel.videoId, mVideo.getCurrentPosition());
            }
            mVideo.release();
            // 系统的remove方法
            Utils.removeViewFormParent(mVideo);
            mVideo = null;
        }
        //注销控制器
        if (mController != null) {
            mController.reset();
            mController = null;
            hasDanmakuView = false;
        }
        mCurPlayerModel = null;
        mVideoContainer = null;
        mCurrentPositionInList = POSITION_UNPLAY;
    }

看看VideoView进入全屏模式的代码

/**
     * 进入全屏
     */
    @Override
    public void startFullScreen() {
        if (mIsFullScreen)
            return;

        ViewGroup decorView = getDecorView();
        if (decorView == null)
            return;

        mIsFullScreen = true;

        //隐藏NavigationBar和StatusBar
        hideSysBar(decorView);

        //从当前FrameLayout中移除播放器视图
        this.removeView(mPlayerContainer);
        //将播放器视图添加到DecorView中即实现了全屏
        decorView.addView(mPlayerContainer);

        setPlayerState(PLAYER_FULL_SCREEN);
    }

通过decorView直接add的playerContainer,startFullScreen方法执行removeView会触发requestLayout导致列表中item的onDetachedFromWindow回调,

而在cleanVideoView()方法中将mVideo即mPlayerContainer中的VideoView置null,

最后decorView中的FrameLayout方法layoutChildren

void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
        final int count = getChildCount();

        final int parentLeft = getPaddingLeftWithForeground();
        final int parentRight = right - left - getPaddingRightWithForeground();

        final int parentTop = getPaddingTopWithForeground();
        final int parentBottom = bottom - top - getPaddingBottomWithForeground();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                final int width = child.getMeasuredWidth();
                final int height = child.getMeasuredHeight();

                int childLeft;
                int childTop;

                int gravity = lp.gravity;
                if (gravity == -1) {
                    gravity = DEFAULT_CHILD_GRAVITY;
                }

                final int layoutDirection = getLayoutDirection();
                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;

                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {

有截取,getChildCount为4,但是final View child = getChildAt(i),此child为null,导致if(child.getVisibility() != GONE)NullPointerException,实际上这个child就是VideoView,被设置成null了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值