Causando OutOfMemoryError en la Animación fotograma a Fotograma en Android

Estoy teniendo un montón de imágenes como cuadros en mis recursos/carpeta dibujable (digamos de aprox 200). Y el uso de estas imágenes quiero ejecutar una animación. El más largo de la animación es de 80Frames. Estoy con éxito capaz de ejecutar la animación haga clic en los botones para algunos, pero para algunos de la animación que me está dando OutOfMemoryError diciendo que VM no puede proporcionar dicha memoria. Es de VM Presupuesto. Puedo contar el tamaño de todas las imágenes que se trata de 10MB. El tamaño de cada imagen es de 320×480 en píxeles.

Yo intente buscar en google y encontré que tengo que llamar explícitamente al Recolector de Basura el uso del Sistema.gc() método. He hecho eso, pero todavía estoy recibiendo algún error en tiempo de la memoria. Puede alguien por favor me ayude a salir de esta.

Código:-

ImageView img = (ImageView)findViewById(R.id.xxx);
img.setBackgroundResource(R.anim.angry_tail_animation);
AnimationDrawable mailAnimation = (AnimationDrawable) img.getBackground();
MediaPlayer player = MediaPlayer.create(this.getApplicationContext(), R.raw.angry);
    if(mailAnimation.isRunning()) {
    mailAnimation.stop();
    mailAnimation.start();
        if (player.isPlaying()) {
        player.stop();
        player.start();
    }
    else {
        player.start();
    }
}
else {
    mailAnimation.start();
        if (player.isPlaying()) {
        player.stop();
        player.start();
    }
    else {
        player.start();
    }
}

Este es el código que he escrito en el clic de un Botón…..

Archivo de recursos dentro de res/imagen/anim

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true" >

<item android:drawable="@drawable/cat_angry0000" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0001" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0002" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0003" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0004" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0005" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0006" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0007" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0008" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0009" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0010" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0011" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0012" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0013" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0014" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0015" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0016" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0017" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0018" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0019" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0020" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0021" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0022" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0023" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0024" android:duration="50"/>

<item android:drawable="@drawable/cat_angry0025" android:duration="50"/>

</animation-list>

** El de arriba es el archivo de recursos utilizados en setBackgroundResource, igual que yo estoy teniendo más de 10 archivo para otro tipo de animación. **

Registro De Error De

01-16 22:23:41.594: E/AndroidRuntime(399): FATAL EXCEPTION: main
01-16 22:23:41.594: E/AndroidRuntime(399): java.lang.IllegalStateException: Could not execute method of the activity
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.view.View$1.onClick(View.java:2144)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.view.View.performClick(View.java:2485)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.view.View$PerformClick.run(View.java:9080)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.os.Handler.handleCallback(Handler.java:587)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.os.Handler.dispatchMessage(Handler.java:92)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.os.Looper.loop(Looper.java:123)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.app.ActivityThread.main(ActivityThread.java:3683)
01-16 22:23:41.594: E/AndroidRuntime(399):  at java.lang.reflect.Method.invokeNative(Native Method)
01-16 22:23:41.594: E/AndroidRuntime(399):  at java.lang.reflect.Method.invoke(Method.java:507)
01-16 22:23:41.594: E/AndroidRuntime(399):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-16 22:23:41.594: E/AndroidRuntime(399):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-16 22:23:41.594: E/AndroidRuntime(399):  at dalvik.system.NativeStart.main(Native Method)
01-16 22:23:41.594: E/AndroidRuntime(399): Caused by: java.lang.reflect.InvocationTargetException
01-16 22:23:41.594: E/AndroidRuntime(399):  at java.lang.reflect.Method.invokeNative(Native Method)
01-16 22:23:41.594: E/AndroidRuntime(399):  at java.lang.reflect.Method.invoke(Method.java:507)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.view.View$1.onClick(View.java:2139)
01-16 22:23:41.594: E/AndroidRuntime(399):  ... 11 more
01-16 22:23:41.594: E/AndroidRuntime(399): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.content.res.Resources.loadDrawable(Resources.java:1709)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.content.res.Resources.getDrawable(Resources.java:581)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.drawable.AnimationDrawable.inflate(AnimationDrawable.java:267)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:787)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.graphics.drawable.Drawable.createFromXml(Drawable.java:728)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.content.res.Resources.loadDrawable(Resources.java:1694)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.content.res.Resources.getDrawable(Resources.java:581)
01-16 22:23:41.594: E/AndroidRuntime(399):  at android.view.View.setBackgroundResource(View.java:7533)
01-16 22:23:41.594: E/AndroidRuntime(399):  at talking.cat.CatActivity.middleButtonClicked(CatActivity.java:83)

Misma manera que he diferentes botones para diferentes animación…
Gracias

  • Yeah buddy es un gran problema de android.Yo siempre la cara pero didnot encontrar la solución particular aunque.. 😉
  • Gracias por tu respuesta pero necesito saber algo de esto…….
  • Puedes publicar algún código aquí…. que nos puede ayudar a entender mejor …
  • lo que están realizando pruebas en? Un dispositivo real, emulador?
  • Estoy a probarlo en el Emulador de ahora…
  • Gracias por tu respuesta..a Ver ahora que he puesto algún fragmento de código….
  • Por favor, cualquiera tener alguna idea de que me haga saber, realmente necesito una solución para esto. Gracias
  • es posible que ustedes no están dando su emulador de suficiente memoria RAM?
  • has leído esto? developer.android.com/resources/articles/… no puedo estar seguro si este es el problema (ya que sólo ha proporcionado el código para el botón del onClickListener) pero es que vale la pena leer… fugas de toda la Actividad del contexto nunca es una buena cosa. este podría ser el problema?
  • más código sería útil si usted quiere a alguien para intentar encontrar el problema :).
  • Gracias por su respuesta. Dado 512 MB de memoria para emulador y también modificar el valor predeterminado de la memoria en eclipse.archivo ini de 256 mb a 512 mb. No he leído el artículo, pero ahora va a través de él. Gracias una vez más
  • He publicado todo el código aquí. Resto de las cosas son las mismas que el anterior. Qué va a cambiar es el archivo de recursos de archivos de audio y nada más. Entonces también yo trato de poner todo.

InformationsquelleAutor Scorpion | 2012-01-01

10 Kommentare

  1. 25

    Supongo que la animación fotograma comprimir las imágenes (PNG o JPG). El tamaño comprimido no es útil para el cálculo de cuánta memoria se necesita para mostrarlos. Para eso, usted necesita pensar acerca de el tamaño sin comprimir. Este será el número de píxeles (320×480) multiplicado por el número de bytes por píxel, lo que típicamente es de 4 (32 bits). Para sus imágenes, a continuación, cada uno será 614,400 bytes. Para el 26 de animación con fotogramas de ejemplo que usted proporcionó, que requerirá de un total de 15,974,400 bytes para mantener el crudo de mapa de bits de datos para todos los fotogramas, sin contar el objeto de sobrecarga.

    Mirando el código fuente de AnimationDrawable, parece que carga todas las imágenes en la memoria a la vez, lo que sería, básicamente, tienen que hacer para un buen rendimiento.

    Si se puede asignar la cantidad de memoria o no es muy dependiente del sistema. Yo por lo menos recomiendo probar esto en un dispositivo real, en lugar de el emulador. También puede intentar ajustar el emulador disponible del tamaño de la memoria RAM, pero esto es sólo una suposición.

    Hay formas de usar BitmapFactory.inPreferredConfig para cargar mapas de bits en una memoria más eficiente en formato RGB 565 (en lugar de ARGB 8888). Esto le puede ahorrar algo de espacio, pero todavía podría no ser suficiente.

    Si usted no puede asignar esa cantidad de memoria a la vez, usted tiene que considerar otras opciones. La mayoría de los gráficos de alto rendimiento de las aplicaciones (por ejemplo, juegos) dibuja su gráfica a partir de la combinación de gráficos pequeños (sprites) o 2D o 3D primitivas (rectángulos, triángulos). Dibujo de una pantalla de mapa de bits para cada fotograma es efectivamente el mismo que el renderizado de vídeo; no necesariamente la más eficiente.

    Hace todo el contenido de su animación cambiar con cada fotograma? Otro de optimización podría ser para animar sólo la parte que en realidad cambia, y picar hasta que los mapas de bits de la cuenta para que.

    Para resumir, usted necesita encontrar una manera de llamar la animación utilizando menos memoria. Hay muchas opciones, pero depende mucho de cómo la animación necesidades para buscar.

    • LYRICSBOY ,Gracias por tu respuesta. Usted podría escuchado acerca de los Talking Tom Cat, juego en android y también a otros. Yo quiero exactamente lo mismo en mi app. Estoy teniendo marcos de tamaño de 320×480 píxeles, como he dicho antes, así que la búsqueda acerca de los sprites en google y encontré que los sprites son útiles para el pequeño tamaño de las imágenes no para grandes archivos png. Y de mapa de bits de la Fábrica no sé cómo puedo cargar todo esto se enmarca en un objeto de mapa de bits o de cómo ejecutar mi animación usando clases de mapa de bits en lugar de AnimationDrawable.
    • Parece que usted puede utilizar AnimationDrawable en el código (en lugar de XML) y el uso addFrame(Drawable, int) a pasar su propio dibujables, también creado en el código mediante BitmapDrawable para envolver Bitmapcreado por el uso de BitmapFactory. O usted puede tratar de crear su propia subclase de DrawableContainer (la superclase de AnimationDrawable) que se adapta más a tus necesidades. O usted podría crear un juego al estilo de dibujo de bucle que se dispara como a menudo como sea posible, pero no más rápido que la velocidad deseada y carga los mapas de bits de los recursos en algún tipo de caché inteligente.
    • LYRICSBOY, Puede usted por favor me guía ¿cómo puedo utilizar BitmapFactory , BitmapDrawable & mapa de bits para mi aplicación como nunca he usado este las cosas antes nunca. He utilizado addFrame en mi código antes de este AnimationDrawable pero en que estoy obteniendo el mismo error. Pero no los he usado hilo para ejecutar la animación. Hace alguna diferencia?
    • El código asociado con este artículo tiene algunos ejemplos de cómo usar BitmapFactory. Una rápida búsqueda debe encontrar varios más.
  2. 53

    Yo tenía el mismo problema. Android cargas de todos los dibujables a la vez, por lo que la animación con fotogramas de la causa de este error.

    Me terminó de crear mi propia simple secuencia de animación:

    public class AnimationsContainer {
        public int FPS = 30;  //animation FPS
    
        //single instance procedures
        private static AnimationsContainer mInstance;
    
        private AnimationsContainer() {
        };
    
        public static AnimationsContainer getInstance() {
            if (mInstance == null)
                mInstance = new AnimationsContainer();
            return mInstance;
        }
    
        //animation progress dialog frames
        private int[] mProgressAnimFrames = { R.drawable.logo_30001, R.drawable.logo_30002, R.drawable.logo_30003 };
    
        //animation splash screen frames
        private int[] mSplashAnimFrames = { R.drawable.logo_ding200480001, R.drawable.logo_ding200480002 };
    
    
        /**
         * @param imageView 
         * @return progress dialog animation
         */
        public FramesSequenceAnimation createProgressDialogAnim(ImageView imageView) {
            return new FramesSequenceAnimation(imageView, mProgressAnimFrames);
        }
    
        /**
         * @param imageView
         * @return splash screen animation
         */
        public FramesSequenceAnimation createSplashAnim(ImageView imageView) {
            return new FramesSequenceAnimation(imageView, mSplashAnimFrames);
        }
    
        /**
         * AnimationPlayer. Plays animation frames sequence in loop
         */
    public class FramesSequenceAnimation {
        private int[] mFrames; //animation frames
        private int mIndex; //current frame
        private boolean mShouldRun; //true if the animation should continue running. Used to stop the animation
        private boolean mIsRunning; //true if the animation currently running. prevents starting the animation twice
        private SoftReference<ImageView> mSoftReferenceImageView; //Used to prevent holding ImageView when it should be dead.
        private Handler mHandler;
        private int mDelayMillis;
        private OnAnimationStoppedListener mOnAnimationStoppedListener;
    
        private Bitmap mBitmap = null;
        private BitmapFactory.Options mBitmapOptions;
    
        public FramesSequenceAnimation(ImageView imageView, int[] frames, int fps) {
            mHandler = new Handler();
            mFrames = frames;
            mIndex = -1;
            mSoftReferenceImageView = new SoftReference<ImageView>(imageView);
            mShouldRun = false;
            mIsRunning = false;
            mDelayMillis = 1000 / fps;
    
            imageView.setImageResource(mFrames[0]);
    
            //use in place bitmap to save GC work (when animation images are the same size & type)
            if (Build.VERSION.SDK_INT >= 11) {
                Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
                int width = bmp.getWidth();
                int height = bmp.getHeight();
                Bitmap.Config config = bmp.getConfig();
                mBitmap = Bitmap.createBitmap(width, height, config);
                mBitmapOptions = new BitmapFactory.Options();
                //setup bitmap reuse options. 
                mBitmapOptions.inBitmap = mBitmap;
                mBitmapOptions.inMutable = true;
                mBitmapOptions.inSampleSize = 1;
            }
        }
    
        private int getNext() {
            mIndex++;
            if (mIndex >= mFrames.length)
                mIndex = 0;
            return mFrames[mIndex];
        }
    
        /**
         * Starts the animation
         */
        public synchronized void start() {
            mShouldRun = true;
            if (mIsRunning)
                return;
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    ImageView imageView = mSoftReferenceImageView.get();
                    if (!mShouldRun || imageView == null) {
                        mIsRunning = false;
                        if (mOnAnimationStoppedListener != null) {
                            mOnAnimationStoppedListener.AnimationStopped();
                        }
                        return;
                    }
    
                    mIsRunning = true;
                    mHandler.postDelayed(this, mDelayMillis);
    
                    if (imageView.isShown()) {
                        int imageRes = getNext();
                        if (mBitmap != null) { //so Build.VERSION.SDK_INT >= 11
                            Bitmap bitmap = null;
                            try {
                                bitmap = BitmapFactory.decodeResource(imageView.getResources(), imageRes, mBitmapOptions);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (bitmap != null) {
                                imageView.setImageBitmap(bitmap);
                            } else {
                                imageView.setImageResource(imageRes);
                                mBitmap.recycle();
                                mBitmap = null;
                            }
                        } else {
                            imageView.setImageResource(imageRes);
                        }
                    }
    
                }
            };
    
            mHandler.post(runnable);
        }
    
            /**
             * Stops the animation
             */
            public synchronized void stop() {
                mShouldRun = false;
            }
        }
    }

    Uso:

    FramesSequenceAnimation anim = AnimationsContainer.getInstance().createSplashAnim(mSplashImageView);
    anim.start();
    • no te olvides de detenerlo…
    • Gracias por tu respuesta. Seguramente se trate de esto. Esperemos que se resuelva mi problema. Una vez más, gracias
    • OnAnimationStoppedListener me está dando error
    • Funciona realmente bien. Para OnAnimationStoppedListener he añadido una interfaz con sólo un método void AnimationStopped(). También he cambiado un poco para que yo pueda tener un oneshot de animación.
    • He mejorar esta clase y subido a github. Por favor, haga clic en aquí que tiene un problema con oom con el fotograma de la animación.
    • Por alguna razón, la animación no es liso y está tomando más tiempo de lo que debería. Mi matriz está construyendo dinámicamente (en el hilo principal) así que me cambié a ArrayList (~200 elementos) y mi intervalo es 34ms (30fps). Alguna sugerencia?
    • href=»https://github.com/tigerjj/FasterAnimationsContainer/issues/1″ >github.com/tigerjj/FasterAnimationsContainer/issues/1
    • Si la animación se ejecuta lento, probablemente debido a que los marcos son cargados en tiempo real… Mi sugerencia sería la de fijar las imágenes del mismo tamaño y tipo, y asegúrese de que «si (Compilación.VERSIÓN.SDK_INT >= 11) {«… se ejecuta el código – se debe utilizar la misma asignación de memoria para nuevas imágenes y ofrecen un mejor rendimiento
    • he descargado el código de github, pero la animación se mantiene constante en un bucle, no deje de recibir llamadas / o onAnimationEnd oyente no recibir llamadas
    • Thnks por sus respuestas . funciona a la perfección . pero necesito para detener la animación después de la ejecución de todos los marcos . como he 81 marcos de animar y deseo ejecutar esta animación de una sola vez, no varias veces . Usted ha mencionado sobre el método stop pero cuando debo llamar a ella .plz dame solo un poco de detalles para detener la animación después de la ejecución de todos los marcos . y hey thnks en anvance
    • en FramesSequenceAnimation.getNext() se puede decir cuando un ciclo se ha terminado. sólo añadir stop() en ese punto. (o mejor aún, agregar «onLoopEnd() call back).

  3. 11

    Me pasé un montón de tiempo en esto y tiene dos soluciones diferentes, tanto de la buena..

    Primer lugar, el problema:
    1) Android carga todas las imágenes en la memoria RAM, sin comprimir en formato de mapa de bits.
    2) Android utiliza los recursos de escala, por lo que en un teléfono con un xxxhdpi de la pantalla (como el LG G3), cada imagen ocupa un montón de espacio, así que rápidamente se queda sin RAM.

    Solución #1

    1) Evita Android de recursos de la escala. 2) Almacena el bytearrays de todos los archivos en la memoria (estos son pequeños, especialmente para archivos Jpeg). 3) Genera mapas de bits de marco-por-marco, por lo que es casi imposible de ejecutar fuera de RAM.

    Desventajas: spams sus registros como Android es la asignación de memoria para los nuevos mapas de bits y el reciclaje de los viejos. También se realiza pésimo en los dispositivos más antiguos (Galaxy S1), pero desempeña muy bien en el presupuesto actual de los teléfonos (lea: $10 Alcatel C1 recogí en BestBuy). La segunda solución a continuación se realiza mejor en dispositivos más antiguos, pero aún podría correr fuera de la RAM en algunas circunstancias.

    public class MyAnimationDrawable {
    public static class MyFrame {
        byte[] bytes;
        int duration;
        Drawable drawable;
        boolean isReady = false;
    }
    
    
    public interface OnDrawableLoadedListener {
        public void onDrawableLoaded(List<MyFrame> myFrames);
    }
    
    public static void loadRaw(final int resourceId, final Context context, final OnDrawableLoadedListener onDrawableLoadedListener) {
        loadFromXml(resourceId, context, onDrawableLoadedListener);
    }
    
    private static void loadFromXml(final int resourceId, final Context context, final OnDrawableLoadedListener onDrawableLoadedListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                final ArrayList<MyFrame> myFrames = new ArrayList<>();
    
                XmlResourceParser parser = context.getResources().getXml(resourceId);
    
                try {
                    int eventType = parser.getEventType();
                    while (eventType != XmlPullParser.END_DOCUMENT) {
                        if (eventType == XmlPullParser.START_DOCUMENT) {
    
                        } else if (eventType == XmlPullParser.START_TAG) {
    
                            if (parser.getName().equals("item")) {
                                byte[] bytes = null;
                                int duration = 1000;
    
                                for (int i=0; i<parser.getAttributeCount(); i++) {
                                    if (parser.getAttributeName(i).equals("drawable")) {
                                        int resId = Integer.parseInt(parser.getAttributeValue(i).substring(1));
                                        bytes = IOUtils.toByteArray(context.getResources().openRawResource(resId));
                                    }
                                    else if (parser.getAttributeName(i).equals("duration")) {
                                        duration = parser.getAttributeIntValue(i, 1000);
                                    }
                                }
    
                                MyFrame myFrame = new MyFrame();
                                myFrame.bytes = bytes;
                                myFrame.duration = duration;
                                myFrames.add(myFrame);
                            }
    
                        } else if (eventType == XmlPullParser.END_TAG) {
    
                        } else if (eventType == XmlPullParser.TEXT) {
    
                        }
    
                        eventType = parser.next();
                    }
                }
                catch (IOException | XmlPullParserException e) {
                    e.printStackTrace();
                }
    
                //Run on UI Thread
                new Handler(context.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if (onDrawableLoadedListener != null) {
                            onDrawableLoadedListener.onDrawableLoaded(myFrames);
                        }
                    }
                });
            }
        }).run();
    }
    
    public static void animateRawManually(int resourceId, final ImageView imageView, final Runnable onStart, final Runnable onComplete) {
        loadRaw(resourceId, imageView.getContext(), new OnDrawableLoadedListener() {
            @Override
            public void onDrawableLoaded(List<MyFrame> myFrames) {
                if (onStart != null) {
                    onStart.run();
                }
    
                animateRawManually(myFrames, imageView, onComplete);
            }
        });
    }
    
    public static void animateRawManually(List<MyFrame> myFrames, ImageView imageView, Runnable onComplete) {
        animateRawManually(myFrames, imageView, onComplete, 0);
    }
    
    private static void animateRawManually(final List<MyFrame> myFrames, final ImageView imageView, final Runnable onComplete, final int frameNumber) {
        final MyFrame thisFrame = myFrames.get(frameNumber);
    
        if (frameNumber == 0) {
            thisFrame.drawable = new BitmapDrawable(imageView.getContext().getResources(), BitmapFactory.decodeByteArray(thisFrame.bytes, 0, thisFrame.bytes.length));
        }
        else {
            MyFrame previousFrame = myFrames.get(frameNumber - 1);
            ((BitmapDrawable) previousFrame.drawable).getBitmap().recycle();
            previousFrame.drawable = null;
            previousFrame.isReady = false;
        }
    
        imageView.setImageDrawable(thisFrame.drawable);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Make sure ImageView hasn't been changed to a different Image in this time
                if (imageView.getDrawable() == thisFrame.drawable) {
                    if (frameNumber + 1 < myFrames.size()) {
                        MyFrame nextFrame = myFrames.get(frameNumber+1);
    
                        if (nextFrame.isReady) {
                            //Animate next frame
                            animateRawManually(myFrames, imageView, onComplete, frameNumber + 1);
                        }
                        else {
                            nextFrame.isReady = true;
                        }
                    }
                    else {
                        if (onComplete != null) {
                            onComplete.run();
                        }
                    }
                }
            }
        }, thisFrame.duration);
    
        //Load next frame
        if (frameNumber + 1 < myFrames.size()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    MyFrame nextFrame = myFrames.get(frameNumber+1);
                    nextFrame.drawable = new BitmapDrawable(imageView.getContext().getResources(), BitmapFactory.decodeByteArray(nextFrame.bytes, 0, nextFrame.bytes.length));
                    if (nextFrame.isReady) {
                        //Animate next frame
                        animateRawManually(myFrames, imageView, onComplete, frameNumber + 1);
                    }
                    else {
                        nextFrame.isReady = true;
                    }
    
                }
            }).run();
        }
    }
    }

    ** Solución #2 **

    Carga el XML de recursos, lo analiza y cargas de los recursos en bruto – evitando así Android de recursos de la escala (que es responsable de la mayoría de los OutOfMemoryExceptions), y crea un AnimationDrawable.

    Ventajas: funciona mejor en dispositivos más antiguos (por ejemplo. Galaxy S1)

    Desventajas: todavía Puede ejecutar fuera de la RAM como es la celebración de todos los mapas de bits sin comprimir en la memoria, pero son más pequeños, ya que no se escalan de la manera en Android normalmente escalas de imágenes)

    public static void animateManuallyFromRawResource(int animationDrawableResourceId, ImageView imageView, Runnable onStart, Runnable onComplete) {
        AnimationDrawable animationDrawable = new AnimationDrawable();
    
        XmlResourceParser parser = imageView.getContext().getResources().getXml(animationDrawableResourceId);
    
        try {
            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_DOCUMENT) {
    
                } else if (eventType == XmlPullParser.START_TAG) {
    
                    if (parser.getName().equals("item")) {
                        Drawable drawable = null;
                        int duration = 1000;
    
                        for (int i=0; i<parser.getAttributeCount(); i++) {
                            if (parser.getAttributeName(i).equals("drawable")) {
                                int resId = Integer.parseInt(parser.getAttributeValue(i).substring(1));
                                byte[] bytes = IoUtils.readBytes(imageView.getContext().getResources().openRawResource(resId));
                                drawable = new BitmapDrawable(imageView.getContext().getResources(), BitmapFactory.decodeByteArray(bytes, 0, bytes.length));
                            }
                            else if (parser.getAttributeName(i).equals("duration")) {
                                duration = parser.getAttributeIntValue(i, 66);
                            }
                        }
    
                        animationDrawable.addFrame(drawable, duration);
                    }
    
                } else if (eventType == XmlPullParser.END_TAG) {
    
                } else if (eventType == XmlPullParser.TEXT) {
    
                }
    
                eventType = parser.next();
            }
        }
        catch (IOException | XmlPullParserException e) {
            e.printStackTrace();
        }
    
        if (onStart != null) {
            onStart.run();
        }
        animateDrawableManually(animationDrawable, imageView, onComplete, 0);
    }
    
    private static void animateDrawableManually(final AnimationDrawable animationDrawable, final ImageView imageView, final Runnable onComplete, final int frameNumber) {
        final Drawable frame = animationDrawable.getFrame(frameNumber);
        imageView.setImageDrawable(frame);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Make sure ImageView hasn't been changed to a different Image in this time
                if (imageView.getDrawable() == frame) {
                    if (frameNumber + 1 < animationDrawable.getNumberOfFrames()) {
                        //Animate next frame
                        animateDrawableManually(animationDrawable, imageView, onComplete, frameNumber + 1);
                    }
                    else {
                        //Animation complete
                        if (onComplete != null) {
                            onComplete.run();
                        }
                    }
                }
            }
        }, animationDrawable.getDuration(frameNumber));
    }

    Si usted todavía está teniendo problemas de memoria, uso de imágenes más pequeñas… o almacenar el nombre del recurso + duración, y generar la matriz de bytes + Imagen en cada fotograma. Que causará seguramente demasiado picar entre marcos, pero utiliza casi a cero la memoria RAM.

    • La solución 1 es la Mejor que he encontrado en horas. Sólo se ha cambiado: bytes = IoUtils.readBytes(contexto.getResources().openRawResource(resId)); A: bytes = IOUtils.toByteArray(contexto.getResources().openRawResource(resId));
    • Gracias por las capturas @MeerschweinBob , yo venía de hacer referencia a mi propia clase. He actualizado la respuesta para utilizar el estándar IOUtils. Me alegro de que (de lo contrario) te ayudó.
    • ¿por qué en la 1ª solución que está ejecutando el siguiente fotograma dos veces en animateRawManually. una vez en el Controlador.postDelayed y una vez en el Hilo ?
    • se puede también explicar la isReady booleano ? para qué es esto ?
    • Se puede poner un ejemplo de cómo el uso de sus soluciones? Aquellos que no están bien versados podría no tener una idea sobre cómo empezar con su código.
    • Muchas gracias! La primera solución funciona como un encanto! 😀
    • Usted sólo necesita llamar a los métodos estáticos, como por ejemplo: loadRaw o animateRawManually

  4. 3

    He creado una clase de animación que muestra los fotogramas basado en el pasado en dibujables recursos y los marcos de las duraciones.

     protected class SceneAnimation{
        private ImageView mImageView;
        private int[] mFrameRess;
        private int[] mDurations;
        private int mDuration;
    
        private int mLastFrameNo;
        private long mBreakDelay;
    
     public SceneAnimation(ImageView pImageView, int[] pFrameRess, int[] pDurations){
            mImageView = pImageView;
            mFrameRess = pFrameRess;
            mDurations = pDurations;
            mLastFrameNo = pFrameRess.length - 1;
    
            mImageView.setImageResource(mFrameRess[0]);
            play(1);
        }
    
        public SceneAnimation(ImageView pImageView, int[] pFrameRess, int pDuration){
            mImageView = pImageView;
            mFrameRess = pFrameRess;
            mDuration = pDuration;
            mLastFrameNo = pFrameRess.length - 1;
    
            mImageView.setImageResource(mFrameRess[0]);
            playConstant(1);
        }
    
        public SceneAnimation(ImageView pImageView, int[] pFrameRess, int pDuration, long pBreakDelay){            
            mImageView = pImageView;
            mFrameRess = pFrameRess;
            mDuration = pDuration;
            mLastFrameNo = pFrameRess.length - 1;
            mBreakDelay = pBreakDelay;
    
            mImageView.setImageResource(mFrameRess[0]);
            playConstant(1);
        }
    
    
        private void play(final int pFrameNo){
            mImageView.postDelayed(new Runnable(){
                public void run() {
                    mImageView.setImageResource(mFrameRess[pFrameNo]);
                    if(pFrameNo == mLastFrameNo)
                        play(0);
                    else
                        play(pFrameNo + 1);
                }
            }, mDurations[pFrameNo]);
        }
    
    
        private void playConstant(final int pFrameNo){
            mImageView.postDelayed(new Runnable(){
                public void run() {                    
                    mImageView.setImageResource(mFrameRess[pFrameNo]);
    
                    if(pFrameNo == mLastFrameNo)
                        playConstant(0);
                    else
                        playConstant(pFrameNo + 1);
                }
            }, pFrameNo==mLastFrameNo && mBreakDelay>0 ? mBreakDelay : mDuration);
        }        
    };

    Es utilizado como esta:

     private ImageView mTapScreenTextAnimImgView;    
    private final int[] mTapScreenTextAnimRes = {R.drawable.tap0001_b, R.drawable.tap0002_b, R.drawable.tap0003_b, 
            R.drawable.tap0004_b, R.drawable.tap0005_b, R.drawable.tap0006_b, R.drawable.tap0005_b, R.drawable.tap0004_b,
            R.drawable.tap0003_b, R.drawable.tap0002_b, R.drawable.tap0001_b};
    private final int mTapScreenTextAnimDuration = 100;
    private final int mTapScreenTextAnimBreak = 500;

    y en onCreate:

     mTapScreenTextAnimImgView = (ImageView) findViewById(R.id.scene1AnimBottom);
        new SceneAnimation(mTapScreenTextAnimImgView, mTapScreenTextAnimRes, mTapScreenTextAnimDuration, mTapScreenTextAnimBreak);
    • Gracias por tu respuesta, voy a probar esto y espero que a mí me funciona.
  5. 2

    He tenido este problema y resuelto por hacer las dos cosas siguientes:

    1. Cortar la resolución de la animación de imágenes en la mitad…de 1/4 del tamaño sin comprimir en bytes.
    2. Poner las imágenes en el dibujable-nodpi carpeta para que no se ajusta por Android para usted.

    Mi animación era todavía no cargar en algunos teléfonos después de realizar el paso 1.
    Paso 2 consiguió trabajo en los teléfonos.

    Espero que esto salva a alguien de algún tiempo.

    EDIT: yo todavía estaba experimentando problemas después de ir a la Actividad que desempeña el AnimationDrawable pero tengo que trabajar ahora. Aquí están las cosas que hice:

    1. No utilice una animación de la lista en xml. En lugar de crear el AnimationDrawable cada vez que se necesite utilizar. De lo contrario, la próxima vez que cargue la animación dibujable de los recursos que todavía va a estar tratando de utilizar los mapas de bits se terminan de reciclaje.
    2. De reciclaje de los mapas de bits en el AnimationDrawable cuando haya terminado de utilizarlo. Esta es la magia que libera la memoria.
    3. Utilizar el Dispositivo Android Monitor a la asignada bytes en la pila.

    Es aquí el código que estoy utilizando para la creación de la AnimationDrawable:

        protected AnimationDrawable CreateLoadingAnimationDrawable()
        {
            AnimationDrawable animation = new AnimationDrawable ();
            animation.OneShot = false;
            for (int i = 0; i < kNumberOfFrames; ++i) {
                int index = (i * 2) + 1;
                string stringIndex = index.ToString ("00");
                string bitmapStringId = kBaseAnimationName + stringIndex;
                int resID = this.Resources.GetIdentifier (bitmapStringId, "drawable", this.PackageName);
                Bitmap bitmap = BitmapFactory.DecodeResource (this.Resources, resID);
                BitmapDrawable frame = new BitmapDrawable (bitmap);
                //Drawable frame = Resources.GetDrawable (resID);
                animation.AddFrame (frame, 111);
            }
            return animation;
        }

    Y el código para liberar los mapas de bits cuando hayas terminado de usarlos. Usted puede hacer esto en OnPause o OnDestroy. _loadingAnimation es mi AnimationDrawable creado anteriormente. Me encantaría saber lo que SetCallback () ¿para usted en este caso. He copiado de que en algún otro lugar ASÍ.

            if (_loadingAnimation != null) {
                _loadingAnimation.Stop ();
                _loadingImageView.SetBackgroundResource (Resource.Drawable.loading_anim_full7001);
                for (int i = 0; i < _loadingAnimation.NumberOfFrames; ++i) {
                    BitmapDrawable frame = _loadingAnimation.GetFrame (i) as BitmapDrawable;
                    if (frame != null) {
                        Android.Graphics.Bitmap bitmap = frame.Bitmap;
                        bitmap.Recycle ();
                        frame.SetCallback(null);
                    }
                }
                _loadingAnimation.SetCallback(null);
                _loadingAnimation = null;
            }

    Ted

    • Esto funcionó muy bien para mí y es la más sencilla de implementar. Gracias!
    • Me alegro de que esto ayudó a alguien!
    • por favor que me conteste aquí también. stackoverflow.com/q/45709531/3671748
    • Me estoy perdiendo algo, o ¿qué pasa con la extraña capitalización del código? string en lugar de String, etc?
  6. 1

    Similar a la de otras respuestas, el uso de rxjava:

    public final class RxSequenceAnimation {
        private static final int[] PNG_RESOURCES = new int[]{
                R.drawable.sequence_frame_00,
                R.drawable.sequence_frame_01,
                R.drawable.sequence_frame_02
        };
        private static final String TAG = "rx-seq-anim";
        private final Resources mResource;
        private final ImageView mImageView;
        private final byte[][] RAW_PNG_DATA = new byte[PNG_RESOURCES.length][];
        private final byte[] buff = new byte[1024];
        private Subscription sub;
    
        public RxSequenceAnimation(Resources resources, ImageView imageView) {
            mResource = resources;
            mImageView = imageView;
        }
    
        public void start() {
            sub = Observable
                    .interval(16, TimeUnit.MILLISECONDS)
                    .map(new Func1<Long, Bitmap>() {
                        @Override
                        public Bitmap call(Long l) {
                            int i = (int) (l % PNG_RESOURCES.length);
                            if (RAW_PNG_DATA[i] == null) {
                                //read raw png data (compressed) if not read already into RAM
                                try {
                                    RAW_PNG_DATA[i] = read(PNG_RESOURCES[i]);
                                } catch (IOException e) {
                                    Log.e(TAG, "IOException " + String.valueOf(e));
                                }
                                Log.d(TAG, "decoded " + i + " size " + RAW_PNG_DATA[i].length);
                            }
                            //decode directly from RAM - only one full blown bitmap is in RAM at a time
                            return BitmapFactory.decodeByteArray(RAW_PNG_DATA[i], 0, RAW_PNG_DATA[i].length);
                        }
                    })
                    .subscribeOn(Schedulers.newThread())
                    .onBackpressureDrop()
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnNext(new Action1<Bitmap>() {
                        @Override
                        public void call(Bitmap b) {
                            mImageView.setImageBitmap(b);
                        }
                    })
                    .subscribe(LogErrorSubscriber.newInstance(TAG));
        }
    
        public void stop() {
            if (sub != null) {
                sub.unsubscribe();
            }
        }
    
        private byte[] read(int resId) throws IOException {
            return streamToByteArray(inputStream(resId));
        }
    
        private InputStream inputStream(int id) {
            return mResource.openRawResource(id);
        }
    
        private byte[] streamToByteArray(InputStream is) throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int i;
            while ((i = is.read(buff, 0, buff.length)) > 0) {
                baos.write(buff, 0, i);
            }
            byte[] bytes = baos.toByteArray();
            is.close();
            return bytes;
        }
    }
  7. 1

    He portado una solución a Xamarin Android e hizo algunas mejoras.

    Funciona bien con los cambios de orientación y especialmente con las imágenes alrededor de 300 de anchura y de altura (el más grande de la imagen, más tiempo se tarda en cargar la imagen, el más grande es el parpadeo).

    using Android.Content;
    using Android.Graphics;
    using Android.OS;
    using Android.Widget;
    using System;
    
    namespace ...Droid.Util
    {
        public class FramesSequenceAnimation
        {
            private int[] animationFrames;
            private int currentFrame;
            private bool shouldRun;   //true if the animation should continue running. Used to stop the animation
            private bool isRunning;   //true if the animation currently running. prevents starting the animation twice
            private ImageView imageview;
            private Handler handler;
            private int delayMillis;
            private bool oneShot = false;
            private FramesSequenceAnimationListener onAnimationStoppedListener;
            private Bitmap bitmap = null;
            private BitmapFactory.Options bitmapOptions;
            private Action action;
    
            private static object Lock = new object();
    
            public interface FramesSequenceAnimationListener
            {
                void AnimationStopped();
            }
    
            public void SetFramesSequenceAnimationListener(FramesSequenceAnimationListener onAnimationStoppedListener)
            {
                this.onAnimationStoppedListener = onAnimationStoppedListener;
            }
    
            public int GetCurrentFrame()
            {
                return currentFrame;
            }
    
            public void SetCurrentFrame(int currentFrame)
            {
                this.currentFrame = currentFrame;
            }
    
            public FramesSequenceAnimation(FramesSequenceAnimationListener onAnimationStoppedListener, ImageView imageview, int[] animationFrames, int fps)
            {
                this.onAnimationStoppedListener = onAnimationStoppedListener;
                this.imageview = imageview;
                this.animationFrames = animationFrames;
    
                delayMillis = 1000 / fps;
    
                currentFrame = -1;
                shouldRun = false;
                isRunning = false;
                handler = new Handler();
                imageview.SetImageResource(this.animationFrames[0]);
    
                ////use in place bitmap to save GC work (when animation images are the same size & type)
                //if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
                //{
                //   Bitmap bmp = ((BitmapDrawable)imageview.Drawable).Bitmap;
                //   int width = bmp.Width;
                //   int height = bmp.Height;
                //   Bitmap.Config config = bmp.GetConfig();
                //   bitmap = Bitmap.CreateBitmap(width, height, config);
                //   bitmapOptions = new BitmapFactory.Options(); //setup bitmap reuse options
                //   bitmapOptions.InBitmap = bitmap; //reuse this bitmap when loading content
                //   bitmapOptions.InMutable = true;
                //   bitmapOptions.InSampleSize = 1;
                //}
    
                bitmapOptions = newOptions();
                bitmap = decode(bitmapOptions, getNext());
                bitmapOptions.InBitmap = bitmap;
            }
    
            private BitmapFactory.Options newOptions()
            {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.InSampleSize = 1;
                options.InMutable = true;
                options.InJustDecodeBounds = true;
                options.InPurgeable = true;
                options.InInputShareable = true;
                options.InPreferredConfig = Bitmap.Config.Rgb565;
                return options;
            }
    
            private Bitmap decode(BitmapFactory.Options options, int imageRes)
            {
                return BitmapFactory.DecodeResource(imageview.Resources, imageRes, bitmapOptions);
            }
    
            public void SetOneShot(bool oneShot)
            {
                this.oneShot = oneShot;
            }
    
            private int getNext()
            {
                currentFrame++;
                if (currentFrame >= animationFrames.Length)
                {
                    if (oneShot)
                    {
                        shouldRun = false;
                        currentFrame = animationFrames.Length - 1;
                    }
                    else
                    {
                        currentFrame = 0;
                    }
                }
                return animationFrames[currentFrame];
            }
    
            public void stop()
            {
                lock (Lock)
                {
                    shouldRun = false;
                }
            }
    
            public void start()
            {
                lock (Lock)
                {
                    shouldRun = true;
    
                    if (isRunning)
                    {
                        return;
                    }
    
                    Action tempAction = new Action(delegate
                    {
                        if (!shouldRun || imageview == null)
                        {
                            isRunning = false;
                            if (onAnimationStoppedListener != null)
                            {
                                onAnimationStoppedListener.AnimationStopped();
                                onAnimationStoppedListener = null;
                                handler.RemoveCallbacks(action);
                            }
                            return;
                        }
    
                        isRunning = true;
    
                        handler.PostDelayed(action, delayMillis);
    
                        if (imageview.IsShown)
                        {
                            int imageRes = getNext();
                            if (bitmap != null)
                            {
                                if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
                                {
                                    if (bitmap != null && !bitmap.IsRecycled)
                                    {
                                        bitmap.Recycle();
                                        bitmap = null;
                                    }
                                }
    
                                try
                                {
                                    bitmap = BitmapFactory.DecodeResource(imageview.Resources, imageRes, bitmapOptions);
                                }
                                catch (Exception e)
                                {
                                    bitmap.Recycle();
                                    bitmap = null;
                                    Console.WriteLine("Exception: " + e.StackTrace);
                                }
    
                                if (bitmap != null)
                                {
                                    imageview.SetImageBitmap(bitmap);
                                }
                                else
                                {
                                    imageview.SetImageResource(imageRes);
                                    bitmap.Recycle();
                                    bitmap = null;
                                }
                            }
                            else
                            {
                                imageview.SetImageResource(imageRes);
                            }
                        }
                    });
    
                    action = tempAction;
    
                    handler.Post(action);
                }
            }
        }
    }

    Esta es mi pantalla de presentación de clase: (en esta clase lee las imágenes de la carpeta de dibujable que se denominan «splash_0001, splash_0002 …». Así que no es necesario el nombre de sus recursos de imagen en una matriz. Aumentar el número de fotogramas por segundo (FPS) a la velocidad de la animación).

    using Android.App;
    using Android.Content;
    using Android.OS;
    using Android.Widget;
    using ...Droid.Base;
    using ...Droid.Util;
    using System;
    using System.Collections.Generic;
    using static ...Util.FramesSequenceAnimation;
    
    namespace ...Droid.Activities
    {
        [Activity(MainLauncher = true)]
        public class SplashActivity : BaseActivity, FramesSequenceAnimationListener
        {
            private FramesSequenceAnimation framesSequenceAnimation;
    
            private const string
                IMAGE_NAME_PREFIX = "splash_",
                KEY_CURRENT_FRAME = "key_current_frame";
    
            private int FPS = 50;
    
            private int numberOfImages;
    
            protected override OrientationEnum GetOrientation()
            {
                return OrientationEnum.ORIENTATION_CHECK_DEVICE_SIZE;
            }
    
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                SetContentView(Resource.Layout.activity_splash);
    
                RelativeLayout background = FindViewById<RelativeLayout>(Resource.Id.splash_background);
                background.Click += Click;
    
                ImageView imageView = FindViewById<ImageView>(Resource.Id.splash_imageview);
                imageView.Click += Click;
    
                numberOfImages = GetSplashImagesCount();
    
                framesSequenceAnimation = new FramesSequenceAnimation(this, imageView, GetImageResourcesIDs(), FPS);
                framesSequenceAnimation.SetOneShot(true);
    
                if (savedInstanceState != null)
                {
                    int currentFrame = savedInstanceState.GetInt(KEY_CURRENT_FRAME) + 1;
                    if (currentFrame < numberOfImages)
                    {
                        framesSequenceAnimation.SetCurrentFrame(currentFrame);
                    }
                }
    
                framesSequenceAnimation.start();
            }
    
            private int[] GetImageResourcesIDs()
            {
                List<int> list = new List<int>();
    
                for (int i = 1; i <= numberOfImages; i++)
                {
                    var image_name = IMAGE_NAME_PREFIX + i.ToString().PadLeft(4, '0');
                    int resID = Resources.GetIdentifier(image_name, "drawable", PackageName);
                    list.Add(resID);
                }
    
                return list.ToArray();
            }
    
            private int GetSplashImagesCount()
            {
                //Count number of images in drawable folder
                int count = 0;
                var fields = typeof(Resource.Drawable).GetFields();
                foreach (var field in fields)
                {
                    if (field.Name.StartsWith(IMAGE_NAME_PREFIX))
                    {
                        count++;
                    }
                }
    
                return count;
            }
    
            private void Click(object sender, EventArgs e)
            {
                framesSequenceAnimation.SetFramesSequenceAnimationListener(null);
                GoToLoginScreen();
            }
    
            private void GoToLoginScreen()
            {
                Finish();
                StartActivity(new Intent(this, typeof(LoginActivity)));
                OverridePendingTransition(0, Resource.Animation.abc_fade_out);
            }
    
            void FramesSequenceAnimationListener.AnimationStopped()
            {
                GoToLoginScreen();
            }
    
            protected override void OnSaveInstanceState(Bundle outState)
            {
                base.OnSaveInstanceState(outState);
    
                outState.PutInt(KEY_CURRENT_FRAME, framesSequenceAnimation.GetCurrentFrame());
            }
        }
    }
    • usted me ayudó a ahorrar tiempo el día de hoy y funciona perfectamente bien +1
  8. 0

    Es gran problema con el sdk, pero puede ser resuelto mediante el uso de hilos para simultáneamente la carga de las imágenes de mapa de bits en lugar de cargar la imagen completa en el mismo tiempo.

    • Puedo agregar el archivo de recursos de código en la pregunta ahora. Gracias por su rápida respuesta. Por favor, por favor, hágamelo saber donde estoy cometiendo error.
    • JAFFER, Gracias por tu respuesta, pero el uso de hilo ¿cómo puedo cargar mis imágenes? Puede usted por favor darme alguna sugerencia o consejo que ¿cómo debo ir por delante. He encontrado en muchos sitios el uso de mapa de bits o BitmapFactory.las opciones pero no sé nada acerca de cómo utilizar esta clases en mi caso.
  9. 0

    He resuelto mi outOfMemoryError problema al reducir la velocidad de los fotogramas brutalmente y la disminución de las imágenes en gimp. Dependiendo de lo que usted está haciendo probablemente, usted puede conseguir lejos con mucho menos fps de lo que cabría esperar.

  10. 0

    He resolver este problema por poner todas las imágenes en la matriz y el uso de retardo después del espectáculo de cada uno de ellos.
    La matriz de imágenes de origen en res/string
    <!-- Array table for the pictures to show on the spinner-->
    <array name="spinner_list">
    <item>@drawable/arrows_loop__00000_org</item>
    <item>@drawable/arrows_loop__00005_org</item>
    <item >@drawable/arrows_loop__00010_org</item>
    <item>@drawable/arrows_loop__00015_org</item>
    <item >@drawable/arrows_loop__00020_org</item>
    <item >@drawable/arrows_loop__00025_org</item>
    .
    .
    .
    </array>

    Declaro sobre el spinner imageView
    private static ImageView imagespinner;

    A continuación, en mi clase me llaman aquí:

          final TypedArray imgs = getResources().obtainTypedArray(R.array.spinner_list);
        runimage(imgs, imgs.length());

    y, a continuación, en runimage hago el lazo con retraso como este:

            /* handle the spinner frame by frame */

    public void runimage(final TypedArray array, int index) {

      int size = array.length();
    
        if(index<size) {//show in sequence the images
    
        final int localindex= index;
    
            handler.postDelayed(new Runnable() {
                public void run() {
                    imagespinner.setImageResource(array.getResourceId(localindex, -1));//find the picture to show
                    runimage(array,(localindex+1));//because use final arg need to do the increase inside
                }
            }, 55);
    
        }
        else //after show all images go ahead
        {
            textview2.setVisibility(View.VISIBLE);
            handler.postDelayed(myRunnablewait, 2000); //make some time to see text before go to ather fragment
        }
    
    }

    por lo que ejecutar todas las imágenes con 55milsec retraso en la imagespinner. Después de terminar de hacer la nex trabajo.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea