1384 votes

Étrange hors de question de mémoire lors du chargement d’une image à un objet Bitmap

J'ai une vue de liste avec un couple de boutons image sur chaque ligne. Lorsque vous cliquez sur la ligne de la liste, il lance une nouvelle activité. J'ai eu à construire mes propres onglets en raison d'un problème avec l'appareil photo de mise en page. L'activité qui est lancé pour le résultat est une carte. Si je clique sur mon bouton pour lancer l'aperçu de l'image (charger une image de la carte SD) la demande de retour de l'activité de la liste de l'activité à la suite de gestionnaire de relancer ma nouvelle activité qui n'est rien de plus qu'une image widget.

L'aperçu de l'image sur l'affichage de la liste qui est fait avec le curseur et ListAdapter. De ce fait, il est assez simple, mais je ne suis pas sûr de savoir comment je peux mettre une image redimensionnée (I. e. De plus petite taille en bits pas de pixel que le src de l'image bouton à la volée. Alors j'ai juste redimensionné l'image qui est descendu de l'appareil photo du téléphone.

Le problème est que j'obtiens une erreur de mémoire insuffisante lorsqu'il essaie de revenir en arrière et re-lancement de la 2ème activité.

** Est-il possible que je peux construire la liste de l'adaptateur facilement, ligne par ligne, d'où je peux les redimensionner à la volée (peu sage)? Ce serait préférable, car j'ai aussi besoin de faire quelques changements dans les propriétés des widgets/éléments dans chaque ligne que je ne peux pas sélectionner une ligne avec écran tactile en raison de la question de mise au point. (Je peux utiliser roller ball.)

** Je sais que je peux faire une en dehors de la bande de les redimensionner et de les sauver de mon image, mais ce n'est pas vraiment ce que je veux faire, mais un exemple de code pour que ça pourrait être sympa.

Dès que j'ai désactivé l'image sur l'affichage de liste il a bien fonctionné de nouveau.

Pour info: c'est de Cette façon que je le faisais:

String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,
                               DBHelper.KEY_ADDRESS,
                               DBHelper.KEY_CITY,
                               DBHelper.KEY_GPSLONG,
                               DBHelper.KEY_GPSLAT,
                               DBHelper.KEY_IMAGEFILENAME  + ""};
int[] to = new int[] { R.id.businessname,
                       R.id.address,
                       R.id.city,
                       R.id.gpslong,
                       R.id.gpslat,
                       R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

R.id.imagefilename est ButtonImage.

Voici mon LogCat:


01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed

Moi aussi j'ai un nouveau message d'erreur lors de l'affichage d'une image:

01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

919voto

Fedor Points 29890

Pour corriger OutOfMemory vous devriez faire quelque chose comme ça :

Cette option inSampleSize réduit la consommation de mémoire.

Voici une méthode complète. Tout d’abord, il lit taille de l’image sans décoder le contenu lui-même. Puis il trouve la meilleure valeur d’inSampleSize, il faut une puissance de 2. Et enfin, l’image est décodée.

689voto

AdamK Points 1629

La classe de Formation Android , «Afficher les Bitmaps efficacement», offre des renseignements fort pour comprendre et traiter l’exception `` lors du chargement d’images bitmap.

383voto

Thomas Vervest Points 1882

J’ai fait une petite amélioration au code de Fedor. Il fait essentiellement la même, mais sans le (à mon avis) laid tout en boucle et il en résulte toujours une puissance de deux. Félicitations à Fedor pour la fabrication de la solution d’origine, j’ai été bloqué jusqu'à ce que j’ai trouvé sa, et puis j’ai été en mesure de faire celui-ci  :)

238voto

Ephraim Points 1661

Je viens d'iOS expérience et j'étais frustré de découvrir un tel pathétique problème avec quelque chose d'aussi élémentaire que le chargement et l'affichage d'une image. Après tout, tout le monde qui est d'avoir ce problème est d'essayer d'afficher des images de taille raisonnable. De toute façon, ici, sont les deux changements qui fixe mon problème (et de fait mon application est très réactive).

1) Chaque fois que vous effectuez BitmapFactory.decodeXYZ(), assurez-vous de passer en BitmapFactory.Options avec inPurgeable ensemble de true (et de préférence avec de l' inInputShareable également mis à l' true).

2) ne JAMAIS utiliser d' Bitmap.createBitmap(width, height, Config.ARGB_8888). Je veux dire que JAMAIS! Je n'ai jamais eu ce truc de ne pas soulever d'erreur de mémoire, après quelques passes. Aucun montant de la recycle(), System.gc(), quelle que soit aidé. Il a toujours soulevé d'exception. Une autre manière qui fonctionne réellement est d'avoir une fausse image dans votre un drawable (ou une autre image que vous décodés à l'aide de l'étape 1 ci-dessus), redimensionner que tout ce que vous voulez, puis de manipuler l'image résultante (tels que de la transmettre à un Canevas pour plus de fun). Donc, ce que vous devez utiliser à la place est de: Bitmap.createScaledBitmap(srcBitmap, width, height, false). Si, pour quelque raison que ce soit, vous DEVEZ utiliser la force brute de méthode de création, puis au moins passer Config.ARGB_4444.

C'est presque garanti pour vous épargner des heures si pas des jours. Tous les discours sur l'échelle de l'image, etc. ne fonctionne pas vraiment (à moins que vous envisager de faire de mauvaise taille ou la dégradation de l'image d'une solution).

Mais google, sérieux?

98voto

Ses un bug connu, ce n’est pas à cause de fichiers volumineux. Depuis Android met en cache le Drawables, sa va de la mémoire après avoir utilisé quelques images. Mais j’ai trouvé l’autre moyen pour cela, en sautant le système de cache par défaut android.

Soultion: déplacer les images au dossier « assets » et utilisez la fonction suivante pour obtenir des BitmapDrawable

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X