GLSurfaceView黑屏问题解决

2023-10-26

问题列表

  1. 打开其他页面返回当前页面 GLSurfaceView会有短暂黑屏
  2. 按HOME键回到后台再切换回来 GLSurfaceView会有短暂黑屏

分析

以上问题 总结下就是回到后台后再切换到前台, GLSurfaceView会有短暂黑屏

提出问题

1.GLSurfaceView 回到后台做了什么

2.GLSurfaceView 回到前台做了什么

GLSurfaceView 回到后台以及前台,那么关注onWindowVisibilityChanged 就可以了,我们看下相关源码

@Override
 protected void onWindowVisibilityChanged(int visibility) {
     super.onWindowVisibilityChanged(visibility);
     mWindowVisibility = visibility == VISIBLE;
     mRequestedVisible = mWindowVisibility && mViewVisibility;
     updateWindow(false, false);
 }
 
 protected void updateWindow(boolean force, boolean redrawNeeded) {
     if (!mHaveFrame) {
         return;
     }
     ViewRootImpl viewRoot = getViewRootImpl();
     if (viewRoot != null) {
         mTranslator = viewRoot.mTranslator;
     }

     if (mTranslator != null) {
         mSurface.setCompatibilityTranslator(mTranslator);
     }

     int myWidth = mRequestedWidth;
     if (myWidth <= 0) myWidth = getWidth();
     int myHeight = mRequestedHeight;
     if (myHeight <= 0) myHeight = getHeight();

     getLocationInWindow(mLocation);
     final boolean creating = mWindow == null;
     final boolean formatChanged = mFormat != mRequestedFormat;
     final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
     final boolean visibleChanged = mVisible != mRequestedVisible;

     if (force || creating || formatChanged || sizeChanged || visibleChanged
         || mLeft != mLocation[0] || mTop != mLocation[1]
         || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {

         if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
                 + " format=" + formatChanged + " size=" + sizeChanged
                 + " visible=" + visibleChanged
                 + " left=" + (mLeft != mLocation[0])
                 + " top=" + (mTop != mLocation[1]));

         try {
             final boolean visible = mVisible = mRequestedVisible;
             mLeft = mLocation[0];
             mTop = mLocation[1];
             mWidth = myWidth;
             mHeight = myHeight;
             mFormat = mRequestedFormat;

             // Scaling/Translate window's layout here because mLayout is not used elsewhere.

             // Places the window relative
             mLayout.x = mLeft;
             mLayout.y = mTop;
             mLayout.width = getWidth();
             mLayout.height = getHeight();
             if (mTranslator != null) {
                 mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
             }

             mLayout.format = mRequestedFormat;
             mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                           | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                           | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                           | WindowManager.LayoutParams.FLAG_SCALED
                           | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                           | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                           ;
             if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
                 mLayout.privateFlags |=
                         WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
             }
             mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;

             if (mWindow == null) {
                 Display display = getDisplay();
                 mWindow = new MyWindow(this);
                 mLayout.type = mWindowType;
                 mLayout.gravity = Gravity.START|Gravity.TOP;
                 mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
                         mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
                         mStableInsets);
             }

             boolean realSizeChanged;
             boolean reportDrawNeeded;

             int relayoutResult;

             mSurfaceLock.lock();
             try {
                 mUpdateWindowNeeded = false;
                 reportDrawNeeded = mReportDrawNeeded;
                 mReportDrawNeeded = false;
                 mDrawingStopped = !visible;

                 if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);

                 relayoutResult = mSession.relayout(
                     mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                         visible ? VISIBLE : GONE,
                         WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
                         mWinFrame, mOverscanInsets, mContentInsets,
                         mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
                         mNewSurface);
                 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                     reportDrawNeeded = true;
                 }

                 if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
                         + ", vis=" + visible + ", frame=" + mWinFrame);

                 mSurfaceFrame.left = 0;
                 mSurfaceFrame.top = 0;
                 if (mTranslator == null) {
                     mSurfaceFrame.right = mWinFrame.width();
                     mSurfaceFrame.bottom = mWinFrame.height();
                 } else {
                     float appInvertedScale = mTranslator.applicationInvertedScale;
                     mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
                     mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
                 }

                 final int surfaceWidth = mSurfaceFrame.right;
                 final int surfaceHeight = mSurfaceFrame.bottom;
                 realSizeChanged = mLastSurfaceWidth != surfaceWidth
                         || mLastSurfaceHeight != surfaceHeight;
                 mLastSurfaceWidth = surfaceWidth;
                 mLastSurfaceHeight = surfaceHeight;
             } finally {
                 mSurfaceLock.unlock();
             }

             try {
                 redrawNeeded |= creating | reportDrawNeeded;

                 SurfaceHolder.Callback callbacks[] = null;

                 final boolean surfaceChanged = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
                 // 重点关注点1 在window 不显示时,调用了SurfaceHolder的surfaceDestroyed方法 并把mSurfaceCreated=false
                 if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                     mSurfaceCreated = false;
                     if (mSurface.isValid()) {
                         if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
                         callbacks = getSurfaceCallbacks();
                         for (SurfaceHolder.Callback c : callbacks) {
                             c.surfaceDestroyed(mSurfaceHolder);
                         }
                     }
                 }

                 mSurface.transferFrom(mNewSurface);

                 if (visible && mSurface.isValid()) {
                 // 重点关注点2 在window 显示时,会触发这里,先surfaceCreated 后surfaceChanged
                     if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                         mSurfaceCreated = true;
                         mIsCreating = true;
                         if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
                         if (callbacks == null) {
                             callbacks = getSurfaceCallbacks();
                         }
                         for (SurfaceHolder.Callback c : callbacks) {
                             c.surfaceCreated(mSurfaceHolder);
                         }
                     }
                     
                     if (creating || formatChanged || sizeChanged
                             || visibleChanged || realSizeChanged) {
                         if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
                                 + " w=" + myWidth + " h=" + myHeight);
                         if (callbacks == null) {
                             callbacks = getSurfaceCallbacks();
                         }
                         for (SurfaceHolder.Callback c : callbacks) {
                             c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
                         }
                     }
                     if (redrawNeeded) {
                         if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
                         if (callbacks == null) {
                             callbacks = getSurfaceCallbacks();
                         }
                         for (SurfaceHolder.Callback c : callbacks) {
                             if (c instanceof SurfaceHolder.Callback2) {
                                 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
                                         mSurfaceHolder);
                             }
                         }
                     }
                 }
             } finally {
                 mIsCreating = false;
                 if (redrawNeeded) {
                     if (DEBUG) Log.i(TAG, "finishedDrawing");
                     mSession.finishDrawing(mWindow);
                 }
                 mSession.performDeferredDestroy(mWindow);
             }
         } catch (RemoteException ex) {
         }
         if (DEBUG) Log.v(
             TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
             " w=" + mLayout.width + " h=" + mLayout.height +
             ", frame=" + mSurfaceFrame);
     }
 }
 

上边列出了两个重点关注点 ,1是回到后台的逻辑,2是回到前台的逻辑

那么问题的原因就算找到了,找到了的话如何解决。

解决

首先这里回到后台回收是为了回收部分资源,让性能更好利用起来,但是出现了一些体验问题

不建议我们总是违背系统意愿做自己想做的事

解决方案就是不触发回收,如何不触发回收,重写onWindowVisibilityChanged,如下

```
override fun onWindowVisibilityChanged(visibility: Int) {
    super.onWindowVisibilityChanged(View.VISIBLE)
    // 以下是优化建议,在显示不显示时处理一下后台资源
    if (visibility == View.VISIBLE) {
        ResumeThread()
    } else {
        SuspendThread()
    }
}
```
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GLSurfaceView黑屏问题解决 的相关文章

  • 如何从 Android 广播接收器显示对话框?

    理想情况下 我不想启动一项活动来执行此操作 当 WiFi 连接丢失时 我的应用程序需要关闭 因为这对我们来说是一个致命错误 我想显示一条错误消息并让用户按 确定 按钮 然后退出应用程序 解决这个问题的最佳方法是什么 Thanks AFAIK
  • Android TextToSpeech 行为不规则

    更新 经过一番挖掘 我设法在 Logcat 中找到了一些信息 见底部 编辑2 我现在从头开始创建了一个新活动来减少这个问题 它仍然无法正常工作 这是代码 public class MainActivity extends AppCompat
  • 设备锁定时,互联网音乐播放器无法加载歌曲(打瞌睡模式?)

    我正在构建一个音乐播放器 可以播放互联网上的歌曲 我注意到 通常 当一首歌曲结束并且必须加载另一首歌曲时 应用程序不会播放下一首歌曲 我等啊等 终于决定解锁手机以了解发生了什么 令人惊讶的是 设备解锁后立即开始播放以下歌曲 第一次我以为这只
  • 在 IconPageIndicator 中自定义填充和边距

    我正在尝试实现自定义 IconPageIndicator viewpager 我想自定义 com viewpagerindicator IconPageIndicator 中显示的图标的边距和填充 所以我编写了自定义 IconPageInd
  • 将实时 Android 网络摄像头视频上传到 RTP/RTSP 服务器

    我已经做了适当的研究 但仍然缺乏关于我想要实现的目标的信息 因此 我想编写一个应用程序 用户可以在其中录制视频并立即 实时 将视频上传到 RTP RTSP 服务器 服务器端不会有问题 我不清楚的是如何在手机端实现这一点 到目前为止 我的研究
  • 为什么 LocationSettingsResult startResolutionForResult 不调用 onActivityResult?

    我看过这个问答LocationSettingsRequest 对话框 跳过 onActivityResult https stackoverflow com questions 31235564 locationsettingsreques
  • 模拟器的窗口比手机屏幕太大

    我做了一个小例子来测试我的Android环境 当我在AVD上启动执行时 它看起来太大了 就好像它是平板电脑屏幕一样 如何调整大小使其看起来像手机屏幕 Android Studio 2 2更新后就没有了Emulator Tab in Edit
  • Glide:如何使用 Glide v4 调整 gif 大小并将其另存为文件?

    我想调整 gif 文件的大小并保存它 我尝试使用一些建议的方法 但这些方法给出了错误 后来我知道有些方法在 Glide 中已被弃用v4 byte bytes Glide with context asGif load url toBytes
  • Android 自定义对话框中的图标

    有没有一种方法可以在不使用 AlertDialog 方法的情况下在自定义对话框上设置图标 对话框有标题 但缺少漂亮的分隔线和设置图标的功能 但肯定有一种方法可以在不使用 AlertDialog 的情况下获得两者 您可以使用以下代码添加图标
  • 如何将数据从 SQLITE 数据库获取到 Android 中的数组?

    很确定这是一个简单的问题 但我对所有将从游标返回的数据适应不同视图的示例感到困惑 我只想运行原始查询并将返回的每一项数据放入浮点数组中 以便我稍后可以将它们添加起来 我需要为此使用什么 Thanks 当您查询数据库时 您仍然会有一个游标 但
  • 使用 GestureDetector 时出现 NullPointerException

    下面是在发生不同事件时加载两个不同图像的帧动画的代码 第一个事件是在活动开始时 其他的是onTouch 我在哪里利用GestureDetector为了onDown and onScroll 问题是我得到NullPointerExceptio
  • 带 LiveData 的嵌套观察者(观察观察者)

    我有一个案例 我有 BottomNavigationView 其中片段被显示 隐藏而不是添加 替换 因此它们不会每次都经历生命周期 片段1正在观察一个数据库表 片段2正在观察一个不同的 我的目标是调用 onChanged片段2当 on 改变
  • 从壁纸中获取颜色? - 安卓

    如何找到当前壁纸的 平均 颜色并将该颜色设置为我的小部件上的布局 我正在尝试做的一个例子 这是 AccuWeather 上的设置 您可以使用WallpaperManager getWallpaperColors https develope
  • Android 应用安装验证

    我有一个应用程序 其中列出了用户可以安装并赚取积分的一些活动 应用程序列表 现在我主要关心的是安全性 一些用户从模拟器或VPN或其他东西安装应用程序 这样我的客户就无法在Google Play商店中安装应用程序 我见过一些应用程序 如现金海
  • Android 是否可以同时使用前后摄像头[重复]

    这个问题在这里已经有答案了 我想同时使用设备的前置和后置摄像头 在我的应用程序中 屏幕的前半部分将显示后置摄像头的预览 屏幕的下半部分将显示前置摄像头的预览 我尝试过设置两个不同的相机预览 但是当我打开应用程序时 屏幕的前半部分 显示后置相
  • Android 2.3 或更低版本上通知中的可点击自定义视图

    我创建了一个自定义通知布局 其中有一个可单击的按钮 到目前为止 在 Android 3 API 级别 11 或更高版本上可以正常工作 但在 Android 2 3 即ContentIntent来自Notification总是覆盖我的布局并且
  • 蓝牙连接;无法正确发送字符串

    当我需要将字符串从服务器蓝牙套接字发送到客户端蓝牙套接字时 我的程序遇到了麻烦 只要我一次只发送一个字符串 例如聊天 一切都可以正常工作 但是如果我需要在短时间内编写更多字符串 以交换信息 则字符串将不会与客户端代码分离 例如 如果我发送
  • GreenDao交易

    我在用着GreenDao存储大量数据 来自休息服务 我的很多实体都与关系相关 一切都很顺利 但明天我必须实施坚如磐石的工作流程 当我加载数据时我必须检查是否发生错误 如果是这样 我必须确保没有存储任何内容在 SQLite 数据库中 通常我会
  • Android 多用户支持(4.2 中的新功能)对服务器端数据模型(例如 android_id)的影响

    Google 刚刚发布了 Android 4 2 其中支持单个设备上的多个用户配置文件 http developer android com about versions android 4 2 html MultipleUsers htt
  • Android:如何获取小数点后的两位数?不想截断值

    如何获取小数点后仅两位数的双精度值 例如 如果 a 190253 80846153846 那么结果值应该像 a 190253 80 尝试 我尝试过这个 public static DecimalFormat twoDForm new Dec

随机推荐

  • [Python图像处理] 二十九.MoviePy视频编辑库实现抖音短视频剪切合并操作

    该系列文章是讲解Python OpenCV图像处理知识 前期主要讲解图像入门 OpenCV基础用法 中期讲解图像处理的各种算法 包括图像锐化算子 图像增强技术 图像分割等 后期结合深度学习研究图像识别 图像分类应用 希望文章对您有所帮助 如
  • 【质量】代码质量评价标准

    今天来思考下如何评价代码质量 业界公认比较认可的七大标准 可维护性 maintainability 可读性 readability 可扩展性 extensibility 灵活性 flexibility 简洁性 simplicity 可复用性
  • ReentrantReadWriteLock

    一ReentrantReadWriteLock 是Lock的另一种实现方式 我们知道ReentrantLock是一个排他锁 同一时间只允许一个线程访问 而ReentrantReadWriteLock允许多个读线程同时访问 但不允许写线程和读
  • RuntimeError: Address already in use

    Pytorch用多张GPU训练时 会报地址已被占用的错误 其实是端口号冲突了 因此解决方法要么kill原来的进程 要么修改端口号 在代码里重新配置 torch distributed init process group dist init
  • ajax异步加载jqgrid之动态创建

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 之前写过一篇过于ajax异步加载jqgrid的文章 那个只是一个特殊的情况 如果创建不同数据库表的jqgrid 必须分别写servlet dao层和连接池 很麻烦 今天我写
  • Hive insert overwrite 问题

    微信公众号 苏言论 理论联系实际 畅言技术与生活 文章目录 1 测试的版本 2 insert overwrite使用说明 3 示例 4 建议的操作 5 参考链接 1 测试的版本 Apache hive 1 1 0 2 3 1 3 1 0 2
  • vue3 全局批量注册组件

    思路 1 使用 require 提供的函数 context 加载某一个目录下的所有 vue 后缀的文件 2 context 函数会返回一个导入函数 importFn 3 它有一个方法 keys 获取所有的文件路径 4 通过文件路径数组 通过
  • Ubuntu20.04 + 3090 安装nvidia驱动,附加解决重启黑屏卡在 /dev/***: clean, **files,***blocks的问题

    目录 准备 禁用nouveau 解决黑屏问题并安装驱动 参考 准备 首先需要知道当前电脑 服务器的显卡型号 这个自行查找自己电脑配置 查找显卡对应的驱动版本 通过命令ubuntu drivers devices查看当前设备所支持的驱动 带有
  • Android 监控SD卡的插拔状态

    http blog csdn net pasterzhang article details 8151877 我们是以DV6300 T的平台来做测试的 发现有2种方式来检测Android中external media 包括SD卡 USB 的
  • Spring Cloud Feign nested exception is java.lang.IllegalStateException

    Spring Cloud Feign 使用时抛出异常 nested exception is java lang IllegalStateException RequestParam value was empty on parameter
  • 数据结构——广度优先遍历(队列)

    队列的基本操作 include
  • 单片机C语言零基础入门05 - 逻辑运算

    硬件家园单片机C语言零基础入门资料汇总链接 https mp weixin qq com s hMTreNUX V90461tvALjJA 一 逻辑与或非 基础理论 逻辑与或非 运算对象是布尔值 1或0 真或假 类似于数字电路的与门 或门
  • Qt 快速读写Excel指南

    Qt Windows 下快速读写Excel指南 很多人搜如何读写excel都会看到用QAxObject来进行操作 很多人试了之后都会发现一个问题 就是慢 非常缓慢 因此很多人得出结论是QAxObject读写excel方法不可取 效率低 后来
  • c#——简易的客车售票系统

    制作一个简单的客车售票系统 假设客车的座位数是9行4列 使用一个二维数组记录客车售票系统中的所有座位号 并在每个座位号上都显示 有票 然后用户输入一个坐标位置 按回车键 即可将该座位号显示为 已售 程序运行结果如下所示 using Syst
  • Redis的安装与Linux下查看服务安装情况

    Redis的安装 移步到大神博客https www cnblogs com hunanzp p 12304622 html Linux下服务的安装情况 移步到大神博客 https www cnblogs com zyh0430 p 1187
  • SpringMVC ssm 接收 List对象

    ssm接收参数不能为接口类型 因此可以使用ArrayList对象接受前端传来的list对象 RequestMapping list public PageVO
  • jQuery之简单的表单验证

    点击打开链接 html部分
  • HTML单选、多选、按钮、下拉框、文本输入框

  • (文章复现)基于主从博弈的新型城镇配电系统产消者竞价策略

    参考文献 1 陈修鹏 李庚银 夏勇 基于主从博弈的新型城镇配电系统产消者竞价策略 J 电力系统自动化 2019 43 14 97 104 1 基本原理 在竞争性电力市场下 新型城镇配电系统内主要有以下几类主体 电力交易中心和调度部门 产消者
  • GLSurfaceView黑屏问题解决

    问题列表 打开其他页面返回当前页面 GLSurfaceView会有短暂黑屏 按HOME键回到后台再切换回来 GLSurfaceView会有短暂黑屏 分析 以上问题 总结下就是回到后台后再切换到前台 GLSurfaceView会有短暂黑屏 提