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

Android双屏场景使用Presentation切换Activity时闪屏与内存泄漏问题求解

问题解决思路与实现方案

核心问题根因

你遇到的闪烁和内存泄漏问题本质来自两个原因:

  • 现有逻辑中旧Presentation销毁和新Presentation加载存在时序差,副屏会在两个实例切换的间隙显示系统默认内容/前Activity残留
  • 旧Presentation销毁时没有完全清除持有的旧Activity Context、View、回调等引用,被长生命周期对象持有后产生内存泄漏

方案1:最小改动优化现有逻辑

直接调整你现有setActivity方法的执行时序,等新Presentation完成首次绘制后再销毁旧实例,同时增加引用清理逻辑避免内存泄漏:

private void setActivity(Activity activity) {
    final MyPresentation oldPresentation = presentation;
    try {
        presentation = new MyPresentation(activity, getDisplay(activity), activity.getLocalClassName());
        presentation.setCancelable(false);
        presentation.setCanceledOnTouchOutside(false);
        // 监听新Presentation的首次绘制完成事件
        presentation.getWindow().getDecorView().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                // 新实例绘制完成后再销毁旧实例,消除切换间隙
                if (oldPresentation != null && oldPresentation.isShowing()) {
                    try {
                        oldPresentation.dismiss();
                        // 手动清除旧实例所有持有引用,避免内存泄漏
                        oldPresentation.setContentView(null);
                        oldPresentation.setOnDismissListener(null);
                        oldPresentation.setOnCancelListener(null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                // 移除监听器避免内存泄漏
                presentation.getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        });
        presentation.show();
    } catch (Exception e) {
        e.printStackTrace();
        // 异常场景恢复旧实例,避免副屏黑屏
        presentation = oldPresentation;
    }
}

额外注意:

  • 持有presentation变量的类不要用静态引用,如果是单例类要改用WeakReference持有Presentation实例
  • 每个Activity的onDestroy生命周期中,检查当前Presentation持有的Context是否为正在销毁的Activity,如果是要清空对应关联的业务回调

方案2:彻底消除切换闪烁的最优方案

使用全局专属透明Activity承载Presentation,完全避免实例重建:

  • 新建一个无UI的透明Activity,启动模式设置为singleInstance,专门作为Presentation的宿主Context,应用运行期间全程只初始化一次
  • 所有业务Activity切换时都不销毁这个透明Activity,对应的Presentation也不需要重建,副屏不会出现任何切换间隙
  • 应用退出时再销毁该透明Activity和对应的Presentation,完全不会产生内存泄漏

方案3:高版本系统无依赖方案

如果你的应用适配Android 8.0及以上系统,可以直接绕过Presentation实现副屏渲染:

  • 申请SYSTEM_ALERT_WINDOW悬浮窗权限,直接通过WindowManager把自定义View添加到副屏对应的Display上
  • 该方式只需要用ApplicationContext即可实现,不需要依赖任何Activity实例,全程只需要创建一次副屏View,切换Activity完全无闪烁,也不会产生内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 07:54:00