4

once again I need some help:

yesterday I asked this question that was about the way to use a large jpg image as a Bitmap (http://stackoverflow.com/questions/13511657/problems-with-big-drawable-jpg-image) and I resolved myself (Is my own response on that question) but whenever I resume my activity, as it uses that bitmap as the GLRenderer texture it crashes. I've tried many things, the last try was to make that bitmap static in order to keep it as a member variable into the activity but it crashes because, I supose, it looses it's mBuffer.

More details on the Activity code:

I declared it as SingletonInstance into the manifest:

android:launchMode="singleInstance"

in order to keep the tiles for the renderer.

and here some code:

@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();
    }

}

On getTextures method I get few small textures and the largest one as in my last question self response:

    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.
            }
        }
    }

So, again, first time it works great but when I go back I do:

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();
        }
    }   

}

And whan I resume the activity:

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

And it crashes.

Why?? Ok, here is the exception cause on the GLThread:

java.lang.IllegalArgumentException: bitmap is recycled...

I tried this messy stuff because launching more than two times the original activity the application crashes bacuse of this or because of the amount of memory used and now I don't know if revert all these changes or what todo with this.

Is there a good way to keep in memory and usable, by this or another application activity, this bitmap?

Please, I need your advices.

Thanks in advance.

JxXx
  • 111
  • 1
  • 7

2 Answers2

2

Do not handle resources manually or your app's surface will broke up. You can't handle your resources manually.

If you worry about reloading resources and you use API level 11+, you can use setPreserveEGLContextOnPause(). It will perserve your textures and FBOs.

If you can't use API 11+, you can port GLSurfaceView() to your app. You can check my own GLSurfaceView that is ported from ICS.

PS: Sorry about my poor english.

Dalinaum
  • 1,142
  • 13
  • 18
  • I'll give it a chance, I can try setPreserveEGLContextOnPause and preserve the GLSurfaceView instead of re-create it. Don't worry about your english, I'm from Spain and I use to have the same problem. Greetings. – JxXx Nov 28 '12 at 10:12
  • Sorry Dalinaum, I counldn´t have a try on that yet but it sounds that that's my answer. This workarround is on my Life TODO list but I had something very bad that I'm dealing with and I'm not able to spend any time on this. You'll have my answer whenever I try that, trust me, but thanks in advance. – JxXx Dec 10 '12 at 07:51
  • @Dalinaum Thanks for sharing your implementation of GLSurfaceView. I tried it and setPreserveEGLContextOnPause() it's working in Android old versions. – jihonrado Feb 20 '13 at 08:47
0

No. Let Android handle all the resources. You must handle the appropriate events and reload the bitmap when the activity is resumed. You cannot expect, that any OpenGL handles are still valid after the activity has been resumed.

Think of it as in the example of a laptop coming out from hibernation. Although all memory has been restored, you cannot expect that any open socket has still a real active connection going.

I am an Android noobie, so please correct me if I am wrong.

Eiver
  • 2,594
  • 2
  • 22
  • 36
  • Thank you for your answer. You're right Eiver, the point is I create the OpenGL game thread on each oncreate but, as the texture bitmaps costs tons of memory resources and the tiles calculation cost long processor time in my game I NEED to keep them usable for the activity, that's the reason I refactored the activity to a single instance one with some static fields. If I left Android to manage memory some times it crashes because an outofmemory exception... – JxXx Nov 24 '12 at 10:35
  • When you close an application in Android, it is the OS who decides if the app should be really closed. If so, then Android will save the state of your app(looks like a memory dump to me), and it will restored later. So your memory will be preserved, but OpenGL and all its resources will be released and a new instance of OpenGL will be loaded on resume. Would it be possible if you did all your tiles calculation and textures outside of OpenGL (store it in a byte[] or something). Then on Resume just generate OpenGL texture from byte array - no recalculation necessary, only data transfer to OpenGL – Eiver Nov 26 '12 at 09:48