欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

【Android】Jetpack全组件实战开发短视频应用App(二十三)

程序员文章站 2022-06-16 18:38:16
前言这一篇我们主要是完成视频的无缝续播,从列表到详情,从详情返回列表,我们看下效果实现分三步:第一步:视频切换视频不暂停,防止画面卡顿第二步:公用一个播放器,去除缓冲效果第三步:使用新的PlayerView,防止原来View缺失造成黑色现象首先我们要做的就是页面切换的时候不暂停视频,我们一般是在onPause()方法中调用视频的暂停方法,所以这里我们需要区分下,如果是点击跳转到详情我们就部调用这个暂停方法,这里我们用一个boolean变量shouldPause区分,默认是true,接着我们在...

前言

这一篇我们主要是完成视频的无缝续播,从列表到详情,从详情返回列表,我们看下效果
【Android】Jetpack全组件实战开发短视频应用App(二十三)

实现

分三步:
第一步:视频切换视频不暂停,防止画面卡顿
第二步:公用一个播放器,去除缓冲效果
第三步:使用新的PlayerView,防止原来View缺失造成黑色现象

首先我们要做的就是页面切换的时候不暂停视频,我们一般是在onPause()方法中调用视频的暂停方法,所以这里我们需要区分下,如果是点击跳转到详情我们就部调用这个暂停方法,这里我们用一个boolean变量shouldPause区分,默认是true,接着我们在onPause方法中坐下判断,这里只要是需要用到无缝续播的地方我们都这样做

    @Override
    public void onPause() {
        //如果是跳转到详情页,咱们就不需要 暂停视频播放了
        //如果是前后台切换 或者去别的页面了 都是需要暂停视频播放的
        if (shouldPause) {
            playDetector.onPause();
        }
        super.onPause();
    }

那我们什么时候把这个值变成false呢?就是在我们点击这个这条item的时候,所以我们需要在FeedAdapter点击事件加一个方法,

 holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
				//....
                onStartFeedDetailActivity(feed);
               //....
            }
        });
public void onStartFeedDetailActivity(Feed feed) {

    }

需要 把这个变量变成false的地方就复写这个方法即可,比如我们的HomeFragment

  @Override
            public void onStartFeedDetailActivity(Feed feed) {
                boolean isVideo = feed.itemType == Feed.TYPE_VIDEO;
                shouldPause = !isVideo;
            }

这样我们就先完成了第一步,切换视频视频不暂停,接下来我们 就要完成第二步,我们需要公用一个播放器,这个比较简单,就是我们通过首页传递过来的category获取播放器实例即可

第三步是需要一个新的PlayerView,这里我们跳转过去需要全屏播放,所以我们需要写一个FullScreenPlayerView,我们 之前写过ListPlayerView,我们只需要继承它然后复写一些方法即可

public class FullScreenPlayerView extends ListPlayerView {
    private PlayerView exoPlayerView;

    public FullScreenPlayerView(@NonNull Context context) {
        this(context, null);
    }

    public FullScreenPlayerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FullScreenPlayerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public FullScreenPlayerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        exoPlayerView = (PlayerView) LayoutInflater.from(context).inflate(R.layout.layout_exo_player_view, null, false);
    }

    @Override
    protected void setSize(int widthPx, int heightPx) {
        if (widthPx >= heightPx) {
            super.setSize(widthPx, heightPx);
            return;
        }

        int maxWidth = PixUtils.getScreenWidth();
        int maxHeight = PixUtils.getScreenHeight();

        ViewGroup.LayoutParams params = getLayoutParams();
        params.width = maxWidth;
        params.height = maxHeight;
        setLayoutParams(params);

        FrameLayout.LayoutParams coverLayoutParams = (LayoutParams) cover.getLayoutParams();
        coverLayoutParams.width = (int) (widthPx / (heightPx * 1.0f / maxHeight));
        coverLayoutParams.height = maxHeight;
        coverLayoutParams.gravity = Gravity.CENTER;
        cover.setLayoutParams(coverLayoutParams);
    }

    @Override
    public void setLayoutParams(ViewGroup.LayoutParams params) {
        if (mHeightPx > mWidthPx) {
            int layoutWidth = params.width;
            int layoutheight = params.height;
            ViewGroup.LayoutParams coverLayoutParams = cover.getLayoutParams();
            coverLayoutParams.width = (int) (mWidthPx / (mHeightPx * 1.0f / layoutheight));
            coverLayoutParams.height = layoutheight;

            cover.setLayoutParams(coverLayoutParams);
            if (exoPlayerView != null) {
                ViewGroup.LayoutParams layoutParams = exoPlayerView.getLayoutParams();
                if (layoutParams != null && layoutParams.width > 0 && layoutParams.height > 0) {
                    float scalex = coverLayoutParams.width * 1.0f / layoutParams.width;
                    float scaley = coverLayoutParams.height * 1.0f / layoutParams.height;

                    exoPlayerView.setScaleX(scalex);
                    exoPlayerView.setScaleY(scaley);
                }
            }
        }
        super.setLayoutParams(params);
    }

    @Override
    public void onActive() {
        PageListPlay pageListPlay = PageListPlayManager.get(mCategory);
        PlayerView playerView = exoPlayerView;//pageListPlay.playerView;
        PlayerControlView controlView = pageListPlay.controlView;
        SimpleExoPlayer exoPlayer = pageListPlay.exoPlayer;
        if (playerView == null) {
            return;
        }

        //主动关联播放器与exoplayerview
        pageListPlay.switchPlayerView(playerView, true);
        ViewParent parent = playerView.getParent();
        if (parent != this) {

            if (parent != null) {
                ((ViewGroup) parent).removeView(playerView);
            }

            ViewGroup.LayoutParams coverParams = cover.getLayoutParams();
            this.addView(playerView, 1, coverParams);
        }

        ViewParent ctrlParent = controlView.getParent();
        if (ctrlParent != this) {
            if (ctrlParent != null) {
                ((ViewGroup) ctrlParent).removeView(controlView);
            }
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.BOTTOM;
            this.addView(controlView, params);
        }

        //如果是同一个视频资源,则不需要从重新创建mediaSource。
        //但需要onPlayerStateChanged 否则不会触发onPlayerStateChanged()
        if (TextUtils.equals(pageListPlay.playUrl, mVideoUrl)) {
            onPlayerStateChanged(true, Player.STATE_READY);
        } else {
            MediaSource mediaSource = PageListPlayManager.createMediaSource(mVideoUrl);
            exoPlayer.prepare(mediaSource);
            exoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
            pageListPlay.playUrl = mVideoUrl;
        }
        controlView.show();
        controlView.setVisibilityListener(this);
        exoPlayer.addListener(this);
        exoPlayer.setPlayWhenReady(true);
    }

    @Override
    public void inActive() {
        super.inActive();
        PageListPlay pageListPlay = PageListPlayManager.get(mCategory);
        //主动切断exoplayer与视频播放器的联系
        pageListPlay.switchPlayerView(exoPlayerView, false);
    }
}

简单解释下,我们通过复写setSize方法设置PlayerView的宽高和封面的宽高,exoplayer不需要在这里设置宽高,因为这个时候还没有添加到playerview中,我们是在onActive方法中添加的,同时它的宽和高和视频的封面宽和高一致;我们通过复写onActive方法实现播放器和我们这个PlayerView的关联,复写inActive方法切断 联系

  public void switchPlayerView(PlayerView newPlayerView, boolean attach) {
        playerView.setPlayer(attach ? null : exoPlayer);
        newPlayerView.setPlayer(attach ? exoPlayer : null);
    }

本文地址:https://blog.csdn.net/Greathfs/article/details/107297218