Android的OpenGL:睡觉后疯狂的长宽比

如果我按下了我的android手机上的电源button(或等待它超时),手机进入hibernate状态,醒来后,屏幕宽高比全是怪事。

截图:

破碎

http://i.imgur.com/4C6ID.png

正确

http://i.imgur.com/CNAV0.png

在GameActivity.onCreate()

// Grab display info DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); ACTUAL_SCREEN_WIDTH = (int) dm.widthPixels; ACTUAL_SCREEN_HEIGHT = (int) dm.heightPixels; ACTUAL_DENSITY = dm.density; double scale = ((double) MainMenuActivity.resolutionScale / 100.0); SCREEN_WIDTH = (int) (ACTUAL_SCREEN_WIDTH * scale); SCREEN_HEIGHT = (int) (ACTUAL_SCREEN_HEIGHT * scale); DENSITY = ACTUAL_DENSITY * scale; // Setup graphics requestWindowFeature(Window.FEATURE_NO_TITLE); surface_view = new GLSurfaceView(this); if (SCREEN_WIDTH != ACTUAL_SCREEN_WIDTH || SCREEN_HEIGHT != ACTUAL_SCREEN_HEIGHT) surface_view.getSurfaceHolder().setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT); 

我在GLSurfaceView中正确地重新加载了所有东西(比如打回家,回到游戏中重新加载纹理等等)。

我已经在onWindowFocusChanged中打印出了方向,并且是横向的(如预期的那样)。

如果我不使用setFixedSize(即如果resolutionScale是100),则不会出现问题。 此外,如果在游戏前面出现另一个窗口(如偏好窗口),则问题消失,然后返回游戏。

提前致谢。 自研究干涸以来,我一直在尝试随机的事情大约一个小时。

Solutions Collecting From Web of "Android的OpenGL:睡觉后疯狂的长宽比"

我现在正在处理这个问题,在这一刻,它似乎是一个与SurfaceHolder.setFixedSize()相关的Android错误。

我做什么来获得这些日志是这样的:等待游戏加载,推动电源,让屏幕变空白,再次推动电源(快速),解锁幻灯片(快速)。 顺便说一句,这是HTC Thunderbolt 2.3.4。

这是正常的事件过程(不使用setFixedSize):

 ----- power button pushed ------ JavaMain: onPause: called, thread: 1 ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=1 layout=34 uiMode=17 seq=1509 skin=default} JavaMain: onConfigurationChanged, orientation: 1 thread: 1 JavaMain: mSView(old): 800x480 JavaMain: surfaceChanged: width: 480, height:800, thread: 1 JavaMain: onWindowFocusChanged: called, thread: 1 (screen is now off) ------ power button pushed, and slide-lock undone ----- JavaMain: onResume: called, thread: 1 ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=1510 skin=default} JavaMain: onConfigurationChanged, orientation: 2 thread: 1 JavaMain: mSView(old): 480x800 JavaMain: onWindowFocusChanged: called, thread: 1 JavaMain: surfaceChanged: width: 800, height:480, thread: 1 (back in game) 

请注意,在onPause之后,我的表面视图将重新创build为纵向,而在onResume之后,它将重新转换为横向。 我有screenOrientation设置清单中的横向。

现在看看在相同的序列中发生了什么,但现在使用SurfaceHolder.setFixedSize()(以降低分辨率):

 ----- power button pushed ------- JavaMain: onPause: called, thread: 1 ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=1 layout=34 uiMode=17 seq=1513 skin=default} JavaMain: onConfigurationChanged, orientation: 1 thread: 1 JavaMain: mSView(old): 800x480 JavaMain: surfaceChanged: width: 640, height:384, thread: 1 JavaMain: onWindowFocusChanged: called, thread: 1 (screen is now off) ------ power button pushed, and slide-lock undone ----- JavaMain: onResume: called, thread: 1 ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=1514 skin=default} JavaMain: onConfigurationChanged, orientation: 2 thread: 1 JavaMain: mSView(old): 480x800 JavaMain: onWindowFocusChanged: called, thread: 1 (back in game, with a messed up screen as in OP) 

现在请注意,在onPause之后,surfaceChanged反映了我指定的固定大小,但是在onResume中,表面视图是纵向的(有点意外)。 但是真正缺less的是使用固定大小的参数调用surfaceChanged。 而在你问之前,不要在onConfigurationChanged()中做.setFixedSize()没有任何作用。

更新和解决scheme:

事实上,解决scheme归结为恢复(实际上,从不允许任何更改)我的表面视图。 这是通过在onConfigurationChanged超级调用之后添加以下两行来完成的。 (假设你有以下清单设置)。

 android:configChanges="orientation" android:screenOrientation="landscape" 

这有效地防止了表面视图尺寸被设置为其他任何东西(例如肖像)。 顺便说一句,当我指定的时候,我想要的是screenOrientation = landscape !!! (我在这里看着你,谷歌)

 public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // -- stomp any attempts by the OS to resize my view. // -- Hardcoded values for illustration only. In real life // -- you'll need to save these when the surface view is originally created mSView.getLayoutParams().width = 800; mSView.getLayoutParams().height = 480; } 

你需要调用gl.glViewport(0,0,width,height); 或者类似于你的GL10.Renderer的onSurfaceChanged方法。 我的假设是,当设备从睡眠中醒来时,必须改变视口,但是当您的应用第一次启动时,视口会初始化,这就是为什么它在睡眠之前能够正常工作。

OpenGL状态和暂停/恢复活动

你还应该知道,当你的活动暂停/恢复时,你的OpenGL上下文 (当前所有的状态,如当前的颜色,绑定的纹理等)将会丢失
所以也许你正面临一个上下文丢失的问题。
如果您使用的是GLSurfaceView.Renderer类,则应该在onSurfaceCreated(..)方法中重新设置您的状态。 应该用一些代码更新你的问题。

更新仅供参考,请参阅http://www.youtube.com/watch?v=cdvaPyq_eBU(38:14 分钟)以及setFixedSize(..)

http://developer.android.com/reference/android/view/SurfaceHolder.html#setFixedSize%28int,%20int%29
声明您必须从运行SurfaceView窗口的相同线程调用方法setFixedSize(SCREEN_WIDTH,SCREEN_HEIGHT) 。 似乎你是从你的UI线程而不是渲染线程设置它。

你需要做三个步骤:

  1. AndroidManifest.xml – android:configChanges="keyboard|keyboardHidden|screenSize|orientation"
  2. 您的活动布局使用FrameLayout
  3. 在java代码中

    public void onSurfaceChanged(GL10 gl,int w,int h){//您需要testingw> h,然后才能执行graphics初始化…}