You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现包含ExoPlayer的全屏横屏Dialog视频横屏播放?

你的实现方案分析与优化建议

你的这个实现方案是可行的,能基本达成横屏全屏播放的需求,但确实存在一些可以优化的地方,也有更健壮的替代方案,我来帮你拆解下:

现有方案的优缺点

优点

  • 实现逻辑简单直接,通过系统全屏主题+强制横屏的方式快速达成效果
  • 自定义了返回键逻辑,能在全屏状态下直接退出,符合用户直觉

潜在问题

  1. 方向恢复遗漏:如果closeFullscreenDialog方法里没有恢复原Activity的屏幕方向,关闭Dialog后原页面会一直保持横屏,影响后续操作
  2. 生命周期风险:在Dialog的onCreate里设置方向,若遇到Dialog因配置变化(比如系统旋转)重建时,可能出现重复设置或方向错乱的问题
  3. 资源泄漏隐患:没有明确处理ExoPlayer的资源释放,若Dialog意外销毁,可能导致播放器资源无法正常释放

更优的实现方式

方案一:优化现有Dialog逻辑,补充必要处理

如果想继续用原生Dialog,建议补充以下逻辑:

  • 保存原Activity的初始方向,在关闭Dialog时恢复
  • 确保ExoPlayer在Dialog销毁时释放资源
  • 处理配置变化时的方向保持

示例代码补充:

// 保存原Activity的屏幕方向
int originalOrientation = getResources().getConfiguration().orientation;

// 你的Dialog初始化代码
dialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
        // 初始化ExoPlayer并绑定视图
        initExoPlayer();
    } 

    @Override 
    public void onBackPressed() { 
        if (exoPlayerFullscreen) closeFullscreenDialog(); 
        super.onBackPressed(); 
    } 

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        // 恢复原Activity方向
        setRequestedOrientation(originalOrientation);
        // 释放ExoPlayer资源
        if (exoPlayer != null) {
            exoPlayer.release();
            exoPlayer = null;
        }
    }
}; 

// closeFullscreenDialog方法补充
private void closeFullscreenDialog() {
    exoPlayerFullscreen = false;
    dialog.dismiss();
}

方案二:使用DialogFragment替代Dialog(推荐)

DialogFragment拥有更完善的生命周期管理,能更好地处理配置变化和资源回收,是Android官方推荐的弹窗实现方式。

示例代码:

public class FullscreenVideoDialogFragment extends DialogFragment {
    private ExoPlayer exoPlayer;
    private int originalOrientation;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 保存原Activity方向
        originalOrientation = requireActivity().getResources().getConfiguration().orientation;
        // 设置全屏主题
        setStyle(STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.setCanceledOnTouchOutside(false);
        return dialog;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 加载你的视频播放器布局
        return inflater.inflate(R.layout.dialog_fullscreen_video, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // 强制Activity横屏
        requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        // 初始化ExoPlayer
        initExoPlayer(view);
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        super.onDismiss(dialog);
        // 恢复原Activity方向
        requireActivity().setRequestedOrientation(originalOrientation);
        // 释放播放器资源
        if (exoPlayer != null) {
            exoPlayer.release();
            exoPlayer = null;
        }
    }

    private void initExoPlayer(View view) {
        PlayerView playerView = view.findViewById(R.id.fullscreen_player_view);
        exoPlayer = new ExoPlayer.Builder(requireContext()).build();
        playerView.setPlayer(exoPlayer);
        // 设置播放源、播放状态等
        // exoPlayer.setMediaItem(...);
        // exoPlayer.prepare();
        // exoPlayer.play();
    }
}

使用时只需要在Activity中启动DialogFragment:

new FullscreenVideoDialogFragment().show(getSupportFragmentManager(), "fullscreen_video_dialog");

方案三:利用ExoPlayer官方FullscreenHelper(最省心)

ExoPlayer提供了FullscreenHelper工具类,专门用于处理全屏播放的方向切换、状态栏/导航栏隐藏等逻辑,不需要自己手动创建Dialog,直接在当前Activity中切换状态即可。

示例代码:

private FullscreenHelper fullscreenHelper;
private PlayerView playerView;
private boolean isFullscreen = false;
private int originalOrientation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    playerView = findViewById(R.id.player_view);
    fullscreenHelper = new FullscreenHelper(this);
    originalOrientation = getResources().getConfiguration().orientation;

    // 设置全屏点击事件
    playerView.setFullscreenButtonClickListener(v -> toggleFullscreen());
}

private void toggleFullscreen() {
    isFullscreen = !isFullscreen;
    // 切换全屏状态并设置横屏
    fullscreenHelper.setFullscreen(isFullscreen, 
        isFullscreen ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : originalOrientation);
    
    // 切换布局:比如隐藏Activity的其他UI,让PlayerView占满屏幕
    if (isFullscreen) {
        // 隐藏顶部导航栏等
        getSupportActionBar().hide();
    } else {
        getSupportActionBar().show();
    }
}

@Override
public void onBackPressed() {
    if (isFullscreen) {
        toggleFullscreen();
        return;
    }
    super.onBackPressed();
}

这个方案的优势是官方维护,能处理各种边缘情况(比如系统导航栏的隐藏/恢复、方向切换的平滑过渡),不需要自己手动管理Dialog的生命周期。

总结

  • 如果是快速实现简单需求,你的现有方案补充方向恢复和资源释放逻辑后可以使用;
  • 如果追求稳定性和可维护性,推荐用DialogFragment;
  • 如果想更省心地处理全屏播放的所有细节,优先选择ExoPlayer的FullscreenHelper。

内容的提问来源于stack exchange,提问作者dzboot02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:35:06