Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Animación Drawable causando OutOfMemoryError en segunda ejecución en Android

Actualmente estoy desarrollando un juego y estoy intentando usar un AnimationDrawable para mostrar una animación en mi Menú Principal. Cuando ejecuto el juego una vez, funciona perfectamente. Pero si toco el botón de retroceso, cuando abro el juego de nuevo me da OutOfMemorryError. Si golpeo a casa y vuelvo al juego, carga pero no muestra la animación, está vacía donde debería estar.

Creo que cuando se abre el juego de nuevo trata de cargar la animación, pero ya está cargado desde la ejecución anterior, ¿puedo liberar esa memoria de alguna manera? ¿Cómo puedo tratar esa excepción?

Buscando alrededor puedo encontrar que es un problema común en Android, pero no pude encontrar nada útil.

Si es relevante, mis imágenes son 310×316 y tengo 114 cuadros para cargar, la animación se carga en un xml.

Mi clase MainMenu:

public class MainMenuActivity extends Activity{ private String TAG = MainMenuActivity.class.getSimpleName(); ImageView rabbitMenu ; AnimationDrawable ad; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.mainmenu); rabbitMenu = (ImageView) findViewById(R.id.rabbitMenu); rabbitMenu.setImageResource(R.drawable.rabbit_menu_animation); ad = (AnimationDrawable) rabbitMenu.getDrawable(); } public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); ad.start(); } } 

El registro de errores:

 01-31 16:13:11.320: E/AndroidRuntime(19550): FATAL EXCEPTION: main 01-31 16:13:11.320: E/AndroidRuntime(19550): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 01-31 16:13:11.320: E/AndroidRuntime(19550): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 01-31 16:13:11.320: E/AndroidRuntime(19550): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:563) 01-31 16:13:11.320: E/AndroidRuntime(19550): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:439) 

Editar:

Después de la sugerencia @OleGG y ahora la segunda ejecución va bien, pero en la tercera ejecución estoy al parecer tratando de usar un mapa de bits reciclado.

Así que dejé de usar AnimationDrawable, y usé AsncTask para resolver mi problema. Ahora sigo cambiando el fondo del ImageView en mi onProgressUpdate (). Puede no ser el mejor enfoque, pero ahora no estoy teniendo ningún problema! ¡Aquí está mi código de AsyncTask en caso de que alguien tenga el mismo problema!

 private class DrawRabbit extends AsyncTask<Void, Integer, Void> { private boolean running = true; private int fps = 24; private int frame = 10014; private String drawableName; @Override protected Void doInBackground(Void... params) { while (running){ try { if (frame == 10014) Thread.sleep(1000); else Thread.sleep(fps); if (frame < 10160) { frame++; publishProgress(frame); } else running = false; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } protected void onProgressUpdate(Integer... frame) { drawableName = "rm" + frame[0]; int res_id = getResources().getIdentifier(drawableName, "drawable", getPackageName()); rabbitFrame.setBackgroundResource(res_id); } } 

  • Cómo obtener una cadena de attr con el tipo de formato de referencia?
  • Error al inflar el fragmento del diseño android-support-v4
  • Cómo configurar la altura de gridview programáticamente android
  • ¿Por qué los pesos anidados son malos para el rendimiento? ¿Alternativas?
  • Programar de forma programada android: layout_centerHorizontal
  • Cómo implementar un DrawerLayout con un identificador visible
  • Diferencia entre onCreateView y onViewCreated en Fragmento
  • Android: Colocar ImageView en la superposición entre diseños
  • 5 Solutions collect form web for “Animación Drawable causando OutOfMemoryError en segunda ejecución en Android”

    Necesita liberar la memoria utilizada por los mapas de bits, cuando salga de esta pantalla. Por desgracia, para las versiones anteriores de Android (afaik esto fue "fijo" desde 3.0, pero puedo estar equivocado) la memoria de mapas de bits se asigna a través de código nativo y, lo que es triste, la memoria debe ser liberado de forma explícita.

    Por lo tanto, supongo que probar este enfoque:

    1. Mueva el código para el método AnimationDrawable to onResume ().
    2. Agregue el siguiente código para liberar memoria a onPause ().

       ad.stop(); for (int i = 0; i < ad.getNumberOfFrames(); ++i){ Drawable frame = ad.getFrame(i); if (frame instanceof BitmapDrawable) { ((BitmapDrawable)frame).getBitmap().recycle(); } frame.setCallback(null); } ad.setCallback(null); 

    Espero que te ayude.

    Por lo tanto, logro resolver mi problema con este enfoque:

    Creó una AsyncTask para dibujar

     private class DrawRabbit extends AsyncTask<Void, Integer, Void> { private int fps = 24; private int frame = 10014; private String drawableName; @Override protected Void doInBackground(Void... params) { while (running){ try { if (frame == 10014) Thread.sleep(1000); else Thread.sleep(fps); if (frame < 10160) { frame++; publishProgress(frame); } else running = false; } catch (InterruptedException e) { e.printStackTrace(); } } return null; } protected void onProgressUpdate(Integer... frame) { drawableName = "rm" + frame[0]; int res_id = getResources().getIdentifier(drawableName, "drawable", getPackageName()); rabbitFrame.setBackgroundResource(res_id); } } 

    Y arrancarlo enWindowsFocusChanged

     public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) new DrawRabbit().execute((Void)null) ; else running = false; Log.d(TAG,"onFocusChanged"); } 

    Espero que ayude a alguien!

    Usted puede intentar reduciendo el tamaño si las imágenes. Mi caso funcionó.

     int[] frames = {R.drawable.frame1, R.drawable.frame2, R.drawable.frame3}; AnimationDrawable drawable = new AnimationDrawable(); for (int fr : frames) { Bitmap sample = BitmapFactory.decodeResource(mActivity.getResources(), fr); sample = Bitmap.createScaledBitmap(sample, sample.getWidth()/4, sample.getHeight()/4, false); drawable.addFrame(new BitmapDrawable(mActivity.getResources(), sample), 30); } 

    Sólo tiene que añadir "android: largeHeap =" true "" en la etiqueta de aplicación android manifest! 🙂

    Agrega estas dos líneas en tu archivo de manifiesto android android: hardwareAccelerated = "true" and android: largeHeap = "true"

     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xxx.yyy" > <application android:allowBackup="false" android:fullBackupContent="false" android:hardwareAccelerated="true" android:largeHeap="true"> </application> 

    Espero que te ayude.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.