由于“位图被回收”,GLSurfaceView.Renderer在恢复时崩溃

时间:2012-11-23 12:11:55

标签: opengl-es renderer glsurfaceview bitmapfactory recycle

我需要一些帮助:

昨天我问这个问题是关于如何使用大型jpg图像作为位图(http://stackoverflow.com/questions/13511657/problems-with-big-drawable-jpg-image),我解决了我自己(这是我自己对这个问题的回答)但每当我恢复活动时,因为它使用该位图作为GLRenderer纹理,它会崩溃。我已经尝试了很多东西,最后一次尝试是将该位图设置为静态,以便将其作为成员变量保存到活动中但它崩溃了,因为我嘲笑它会丢失它的mBuffer。

有关活动代码的更多详细信息:

我将它声明为SingletonInstance到清单中:

android:launchMode="singleInstance"

为了保留渲染器的图块。

这里有一些代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mGLSurfaceView = new GLSurfaceView(this);
    mGLSurfaceView.setEGLConfigChooser(true);   
    mSimpleRenderer = new GLRenderer(this);

    getTextures();      

    if (!mIsTileMapInitialized){

        tileMap = new LandSquareGrid(1, 1, mHeightmap, mLightmap, false, true, true, 128, true);
        tileMap.setupSkybox(mSkyboxBitmap, true);
        mIsTileMapInitialized = true;
    }

    initializeRenderer();   
    mGLSurfaceView.setRenderer(mSimpleRenderer);

    setContentView( R.layout.game_layout );

    setOnTouchListener();
    initializeGestureDetector();

    myCompassView = (MyCompassView)findViewById(R.id.mycompassview);

    // Once set the content view we can set the TextViews:
    coordinatesText = (TextView) findViewById(R.id.coordDynamicText); 
    altitudeText = (TextView) findViewById(R.id.altDynamicText); 
    directionText = (TextView) findViewById(R.id.dirDynamicText); 

    //if (!mIsGLInitialized){
    mOpenGLLayout = (LinearLayout)findViewById(R.id.openGLLayout);
    mOpenGLLayout.addView(mGLSurfaceView);
    mVirtual3DMap = new Virtual3DMap(mSimpleRenderer, tileMap);

    if (mGameThread == null){
        mGameThread = new Thread(mVirtual3DMap);
        mGameThread.start();
    }

}

在getTextures方法中,我得到的几个小纹理和最大的纹理就像我上一个问题中的自我反应一样:

    if (mTerrainBitmap==null){
        InputStream is = getResources().openRawResource(R.drawable.terrain);
        try {
            // Set terrain bitmap options to 16-bit, 565 format.
            terrainBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
            Bitmap auxBitmap = BitmapFactory.decodeStream(is, null, terrainBitmapOptions);
            mTerrainBitmap = Bitmap.createBitmap(auxBitmap);
        }
        catch (Exception e){

        }
        finally {
            try {
                is.close();
            } 
            catch (IOException e) {
                // Ignore.
            }
        }
    }

所以,第一次它很有效,但当我回去时,我做了:

protected void onPause() {
    super.onPause();
    mGLSurfaceView.onPause();

}
@Override
protected void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    if (mVirtual3DMap != null) {
        try {
            mVirtual3DMap.cancel();
            mGameThread=null;
            mVirtual3DMap = null;
            mGLSurfaceView.destroyDrawingCache();
            mSimpleRenderer=null;
            System.gc();
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }   

}

我恢复了活动:

@Override
protected void onResume() {
    super.onResume();
    mGLSurfaceView.onResume();
    if (mVirtual3DMap != null) {
        try {
            mVirtual3DMap.resume();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

它崩溃了。

为什么?好的,这是GLThread的异常原因:

java.lang.IllegalArgumentException:位图被回收......

我尝试了这个混乱的东西,因为启动了原始活动的两倍多,应用程序崩溃了这个或由于使用的内存量,现在我不知道是否还原所有这些更改或与此相关的东西。

有一种很好的方法可以通过这个或另一个应用程序活动保留内存和可用的位图吗?

请,我需要您的建议。

提前致谢。

2 个答案:

答案 0 :(得分:2)

不要手动处理资源,否则您的应用程序表面就会崩溃。您无法手动处理资源。

如果您担心重新加载资源并且使用API​​级别11+,则可以使用setPreserveEGLContextOnPause()。它将坚持你的纹理和FBO。

如果您无法使用API​​ 11+,则可以将GLSurfaceView()移植到您的应用中。您可以查看从ICS移植的my own GLSurfaceView

PS:抱歉我的英语很差。

答案 1 :(得分:0)

没有。让Android处理所有资源。您必须处理相应的事件并在恢复活动时重新加载位图。您不能指望任何OpenGL句柄在活动恢复后仍然有效。

将其视为从休眠状态出来的笔记本电脑的示例。虽然所有内存都已恢复,但您不能指望任何打开的套接字仍然存在真正的活动连接。

我是Android noobie,所以如果我错了请纠正我。