GLSurfaceView.Renderer аварийно завершает работу при возобновлении работы из-за повторного использования растрового изображения.

еще раз мне нужна помощь:

вчера я задал этот вопрос о том, как использовать большое 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: растровое изображение переработано...

Я пробовал эту грязную вещь, потому что запуская более чем в два раза исходную активность, приложение вылетает из-за этого или из-за объема используемой памяти, и теперь я не знаю, отменить ли все эти изменения или что с этим делать.

Есть ли хороший способ сохранить в памяти и использовать это растровое изображение в той или иной активности приложения?

Пожалуйста, мне нужны ваши советы.

Заранее спасибо.


person JxXx    schedule 23.11.2012    source источник


Ответы (2)


Не управляйте ресурсами вручную, иначе поверхность вашего приложения будет разбита. Вы не можете управлять своими ресурсами вручную.

Если вы беспокоитесь о перезагрузке ресурсов и используете API уровня 11+, вы можете использовать setPreserveEGLContextOnPause(). Он сохранит ваши текстуры и FBO.

Если вы не можете использовать API 11+, вы можете перенести GLSurfaceView() в свое приложение. Вы можете проверить мой собственный GLSurfaceView, перенесенный из ICS.

PS: Извините за мой плохой английский.

person Dalinaum    schedule 27.11.2012
comment
Я дам ему шанс, я могу попробовать setPreserveEGLContextOnPause и сохранить GLSurfaceView вместо его повторного создания. Не беспокойтесь о своем английском, я из Испании, и у меня та же проблема. Привет. - person JxXx; 28.11.2012
comment
Извини, Далинаум, я еще не мог попробовать, но похоже, что это мой ответ. Этот обходной путь находится в моем списке Life TODO, но у меня было что-то очень плохое, с чем я имею дело, и я не могу тратить на это время. Вы получите мой ответ всякий раз, когда я попытаюсь это сделать, поверьте мне, но заранее спасибо. - person JxXx; 10.12.2012
comment
@Dalinaum Спасибо, что поделились своей реализацией GLSurfaceView. Я попробовал это и setPreserveEGLContextOnPause(), он работает в старых версиях Android. - person jihonrado; 20.02.2013

Нет. Позвольте Android управлять всеми ресурсами. Вы должны обрабатывать соответствующие события и перезагружать растровое изображение при возобновлении действия. Вы не можете ожидать, что любые дескрипторы OpenGL останутся действительными после возобновления активности.

Подумайте об этом, как в примере с ноутбуком, выходящим из спящего режима. Хотя вся память была восстановлена, вы не можете ожидать, что какой-либо открытый сокет все еще имеет реальное активное соединение.

Я новичок в Android, поправьте меня, если я ошибаюсь.

person Eiver    schedule 23.11.2012
comment
Спасибо за ваш ответ. Эйвер, вы правы, дело в том, что я создаю игровой поток OpenGL при каждом создании, но, поскольку растровые изображения текстур требуют тонны ресурсов памяти, а вычисление тайлов требует много процессорного времени в моей игре, мне НУЖНО, чтобы они могли использоваться для действия, по этой причине я преобразовал активность в один экземпляр с некоторыми статическими полями. Если я оставлю Android для управления памятью несколько раз, он вылетит из-за исключения нехватки памяти... - person JxXx; 24.11.2012
comment
Когда вы закрываете приложение в Android, именно ОС решает, действительно ли приложение должно быть закрыто. Если это так, то Android сохранит состояние вашего приложения (для меня это выглядит как дамп памяти), и оно будет восстановлено позже. Таким образом, ваша память будет сохранена, но OpenGL и все его ресурсы будут освобождены, а новый экземпляр OpenGL будет загружен при возобновлении работы. Было бы возможно, если бы вы выполняли расчет всех своих плиток и текстур вне OpenGL (хранили бы их в байте [] или что-то в этом роде). Затем в Resume просто сгенерируйте текстуру OpenGL из массива байтов - пересчет не требуется, только передача данных в OpenGL - person Eiver; 26.11.2012