【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