J'ai une vue de liste avec quelques boutons d'image sur chaque ligne. Lorsque vous cliquez sur la ligne de liste, elle lance une nouvelle activité. J'ai dû créer mes propres onglets en raison d'un problème avec la disposition de la caméra. L'activité qui se lance pour le résultat est une carte. Si je clique sur mon bouton pour lancer l'aperçu de l'image (charger une image sur la carte SD), l'application retourne de l'activité à l' listview
activité pour le gestionnaire de résultats pour relancer ma nouvelle activité qui n'est rien de plus qu'un widget d'image.
L'aperçu de l'image sur la vue de liste se fait avec le curseur et ListAdapter
. Cela le rend assez simple, mais je ne sais pas comment je peux mettre une image redimensionnée (c'est-à-dire une taille de bit plus petite pas un pixel comme src
pour le bouton d'image à la volée. Je viens donc de redimensionner l'image qui est sortie 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 de relancer la 2e activité.
- Existe-t-il un moyen de créer facilement l'adaptateur de liste ligne par ligne, où je peux redimensionner à la volée (au niveau des bits )?
Ce serait préférable car je dois également apporter des modifications aux propriétés des widgets / éléments de chaque ligne car je ne peux pas sélectionner une ligne avec l'écran tactile en raison du problème de focus. ( Je peux utiliser le rollerball. )
- Je sais que je peux faire un redimensionnement hors bande et enregistrer mon image, mais ce n'est pas vraiment ce que je veux faire, mais un exemple de code pour cela serait bien.
Dès que j'ai désactivé l'image sur la liste, cela a de nouveau fonctionné correctement.
FYI: Voici comment 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);
Où R.id.imagefilename
est un 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
J'ai également une nouvelle 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
la source
Réponses:
La classe de formation Android , " Affichage efficace des bitmaps ", offre d'excellentes informations pour comprendre et gérer l'exception
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
lors du chargement des bitmaps.Lire les dimensions et le type de bitmap
La
BitmapFactory
classe fournit plusieurs méthodes de décodage (decodeByteArray()
,decodeFile()
,decodeResource()
, etc.) pour créer un àBitmap
partir de diverses sources. Choisissez la méthode de décodage la plus appropriée en fonction de votre source de données d'image. Ces méthodes tentent d'allouer de la mémoire pour le bitmap construit et peuvent donc facilement entraîner uneOutOfMemory
exception. Chaque type de méthode de décodage a des signatures supplémentaires qui vous permettent de spécifier des options de décodage via laBitmapFactory.Options
classe. La définition de lainJustDecodeBounds
propriététrue
pendant le décodage évite l'allocation de mémoire, le retournull
de l'objet bitmap mais le paramétrageoutWidth
,outHeight
etoutMimeType
. Cette technique vous permet de lire les dimensions et le type des données d'image avant la construction (et l'allocation de mémoire) du bitmap.Pour éviter les
java.lang.OutOfMemory
exceptions, vérifiez les dimensions d'une image bitmap avant de la décoder, sauf si vous faites entièrement confiance à la source pour vous fournir des données d'image de taille prévisible qui tiennent confortablement dans la mémoire disponible.Charger une version réduite dans la mémoire
Maintenant que les dimensions de l'image sont connues, elles peuvent être utilisées pour décider si l'image complète doit être chargée en mémoire ou si une version sous-échantillonnée doit être chargée à la place. Voici quelques facteurs à considérer:
Par exemple, cela ne vaut pas la peine de charger une image 1024x768 pixels dans la mémoire si elle sera finalement affichée dans une vignette 128x96 pixels dans un fichier
ImageView
.Pour dire au décodeur de sous-échantillonner l'image, chargez une version plus petite en mémoire, définie
inSampleSize
surtrue
dans votreBitmapFactory.Options
objet. Par exemple, une image avec une résolution de 2048x1536 qui est décodée avec uninSampleSize
de 4 produit un bitmap d'environ 512x384. Le chargement en mémoire utilise 0,75 Mo au lieu de 12 Mo pour l'image complète (en supposant une configuration bitmap deARGB_8888
). Voici une méthode pour calculer une valeur de taille d'échantillon qui est une puissance de deux en fonction d'une largeur et d'une hauteur cibles:Pour utiliser cette méthode, décodez d'abord avec
inJustDecodeBounds
set totrue
, passez les options, puis décodez à nouveau en utilisant la nouvelleinSampleSize
valeur etinJustDecodeBounds
définissez surfalse
:Cette méthode permet de charger facilement un bitmap de taille arbitrairement grande dans un
ImageView
qui affiche une miniature de 100 x 100 pixels, comme indiqué dans l'exemple de code suivant:Vous pouvez suivre un processus similaire pour décoder les bitmaps d'autres sources, en remplaçant la
BitmapFactory.decode*
méthode appropriée si nécessaire.la source
Pour corriger l'erreur OutOfMemory, vous devez faire quelque chose comme ceci:
Cette
inSampleSize
option réduit la consommation de mémoire.Voici une méthode complète. Tout d'abord, il lit la taille de l'image sans décoder le contenu lui-même. Ensuite, il trouve la meilleure
inSampleSize
valeur, ce devrait être une puissance de 2, et enfin l'image est décodée.la source
J'ai apporté une petite amélioration au code de Fedor. Il fait essentiellement la même chose, mais sans la boucle (à mon avis) moche tandis que cela donne toujours une puissance de deux. Félicitations à Fedor pour avoir créé la solution d'origine, j'ai été coincé jusqu'à ce que je trouve la sienne, puis j'ai pu faire celle-ci :)
la source
BitmapFactory.decodeStream()
. N'avez-vous pas à enregistrer une référence à chacun d'eux afin qu'ils puissent être fermés dans unfinally
bloc?Je viens de l'expérience iOS et j'étais frustré de découvrir un problème avec quelque chose d'aussi basique que le chargement et l'affichage d'une image. Après tout, tous ceux qui rencontrent ce problème essaient d'afficher des images de taille raisonnable. Quoi qu'il en soit, voici les deux changements qui ont résolu mon problème (et rendu mon application très réactive).
1) Chaque fois que vous faites
BitmapFactory.decodeXYZ()
, assurez - vous de passer unBitmapFactory.Options
avecinPurgeable
ensemble àtrue
(et de préférenceinInputShareable
également réglétrue
).2) NE JAMAIS utiliser
Bitmap.createBitmap(width, height, Config.ARGB_8888)
. Je veux dire JAMAIS! Je n'ai jamais eu cette chose qui n'a pas soulevé d'erreur de mémoire après quelques passes. Aucun montant derecycle()
,System.gc()
, ce qui a aidé. Cela a toujours soulevé une exception. Une autre façon qui fonctionne réellement est d'avoir une image factice dans vos dessinables (ou une autre Bitmap que vous avez décodée en utilisant l'étape 1 ci-dessus), de la redimensionner à tout ce que vous voulez, puis de manipuler la Bitmap résultante (telle que la transmettre à un canevas) pour plus de plaisir). Donc, ce que vous devez utiliser à la place:Bitmap.createScaledBitmap(srcBitmap, width, height, false)
. Si pour une raison quelconque, vous DEVEZ utiliser la méthode de création de force brute, passez au moinsConfig.ARGB_4444
.C'est presque garanti pour vous faire gagner des heures, voire des jours. Tout ce qui parle de redimensionner l'image, etc. ne fonctionne pas vraiment (sauf si vous envisagez une mauvaise taille ou une image dégradée une solution).
la source
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true;
etBitmap.createScaledBitmap(srcBitmap, width, height, false);
résolu mon problème que j'avais avec une exception de mémoire insuffisante sur Android 4.0.0. Merci mon pote!BitmapFactory.Options.inPurgeable
etBitmapFactory.Options.inInputShareable
sont obsolètes developer.android.com/reference/android/graphics/…C'est un bug connu , ce n'est pas à cause de gros fichiers. Depuis Android met en cache les Drawables, il manque de mémoire après avoir utilisé peu d'images. Mais j'ai trouvé un autre moyen pour cela, en ignorant le système de cache par défaut Android.
Solution : déplacez les images vers le dossier "assets" et utilisez la fonction suivante pour obtenir BitmapDrawable:
la source
J'ai eu ce même problème et l'ai résolu en évitant les fonctions BitmapFactory.decodeStream ou decodeFile et utilisé à la place
BitmapFactory.decodeFileDescriptor
decodeFileDescriptor
semble qu'il appelle différentes méthodes natives que decodeStream / decodeFile.Quoi qu'il en soit, ce qui a fonctionné était le suivant (notez que j'ai ajouté certaines options comme certaines l'ont fait ci-dessus, mais ce n'est pas ce qui a fait la différence. Ce qui est critique est l'appel à BitmapFactory.decodeFileDescriptor au lieu de decodeStream ou decodeFile ):
Je pense qu'il y a un problème avec la fonction native utilisée dans decodeStream / decodeFile. J'ai confirmé qu'une méthode native différente est appelée lors de l'utilisation de decodeFileDescriptor. De plus, ce que j'ai lu est "que les images (bitmaps) ne sont pas allouées de manière Java standard mais via des appels natifs; les allocations se font en dehors du tas virtuel, mais sont prises en compte! "
la source
Je pense que la meilleure façon d'éviter cela
OutOfMemoryError
est d'y faire face et de le comprendre.J'ai créé une application pour provoquer intentionnellement
OutOfMemoryError
et surveiller l'utilisation de la mémoire.Après avoir fait beaucoup d'expériences avec cette application, j'ai les conclusions suivantes:
Je vais d'abord parler des versions du SDK avant Honey Comb.
Bitmap est stocké dans un tas natif, mais il récupérera automatiquement les ordures, appeler recycle () est inutile.
Si {taille de segment de machine virtuelle} + {mémoire de segment de mémoire native allouée}> = {limite de taille de segment de mémoire virtuelle pour le périphérique} et que vous essayez de créer un bitmap, un MOO sera lancé.
AVIS: VM HEAP SIZE est compté plutôt que VM ALLOCATED MEMORY.
La taille du tas de VM ne diminuera jamais après sa croissance, même si la mémoire de VM allouée est réduite.
Vous devez donc garder la mémoire maximale de la machine virtuelle aussi faible que possible pour empêcher la taille du tas de machine virtuelle de devenir trop grande pour économiser la mémoire disponible pour les bitmaps.
Appeler manuellement System.gc () n'a aucun sens, le système l'appellera d'abord avant d'essayer d'augmenter la taille du tas.
La taille de segment de mémoire native ne diminuera jamais trop, mais elle n'est pas prise en compte pour le MOO, donc pas besoin de s'en inquiéter.
Ensuite, parlons du SDK Starts de Honey Comb.
Le bitmap est stocké dans le tas VM, la mémoire native n'est pas comptée pour le MOO.
La condition pour le MOO est beaucoup plus simple: {taille de tas VM}> = {limite de taille de tas VM pour le périphérique}.
Donc, vous avez plus de mémoire disponible pour créer un bitmap avec la même limite de taille de tas, le MOO est moins susceptible d'être levé.
Voici quelques-unes de mes observations sur la collecte des déchets et les fuites de mémoire.
Vous pouvez le voir vous-même dans l'application. Si une activité a exécuté une tâche AsyncTask qui était toujours en cours d'exécution après la destruction de l'activité, l'activité ne sera pas récupérée à la fin de la tâche AsyncTask.
En effet, AsyncTask est une instance d'une classe interne anonyme, il contient une référence de l'activité.
L'appel de AsyncTask.cancel (true) n'arrêtera pas l'exécution si la tâche est bloquée dans une opération d'E / S dans le thread d'arrière-plan.
Les rappels sont également des classes internes anonymes, donc si une instance statique de votre projet les contient et ne les libère pas, la mémoire serait perdue.
Si vous avez planifié une tâche répétée ou retardée, par exemple une minuterie, et que vous n'appelez pas cancel () et purge () dans onPause (), la mémoire serait perdue.
la source
private static class
dans la même classe. Ils ne contiendront aucune référence à l'activité (à moins que vous ne leur en donniez un bien sûr)J'ai récemment vu beaucoup de questions sur les exceptions OOM et la mise en cache. Le guide du développeur a un très bon article à ce sujet, mais certains échouent généralement à l'implémenter de manière appropriée.
Pour cette raison, j'ai écrit un exemple d'application qui illustre la mise en cache dans un environnement Android. Cette implémentation n'a pas encore obtenu de MOO.
Regardez à la fin de cette réponse pour un lien vers le code source.
Exigences:
Fonctionnalités:
ListView
écart, il ne sera pas tout simplement télécharger les bitmaps entreCela ne comprend pas:
Exemple de code:
Les images téléchargées sont des images (75 x 75) de Flickr. Cependant, mettez toutes les URL d'image que vous souhaitez traiter, et l'application les réduira si elles dépassent le maximum. Dans cette application, les URL sont simplement dans un
String
tableau.Le
LruCache
a un bon moyen de gérer les bitmaps. Cependant, dans cette application, je mets une instance d'uneLruCache
dans une autre classe de cache que j'ai créée afin de rendre l'application plus faisable.Les trucs critiques de Cache.java (la
loadBitmap()
méthode est la plus importante):Vous ne devez pas modifier quoi que ce soit dans le fichier Cache.java, sauf si vous souhaitez implémenter la mise en cache du disque.
Les éléments critiques de MainActivity.java:
getView()
est appelé très souvent. Normalement, ce n'est pas une bonne idée de télécharger des images là-bas si nous n'avons pas mis en œuvre une vérification qui nous assure que nous ne démarrerons pas une quantité infinie de threads par ligne. Cache.java vérifie si lerowObject.mBitmapUrl
déjà est dans une tâche et s'il l'est, il n'en commencera pas une autre. Par conséquent, nous ne dépassons probablement pas la restriction de file d'attente de travailAsyncTask
pool.Télécharger:
Vous pouvez télécharger le code source depuis https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .
Derniers mots:
J'ai testé cela depuis quelques semaines maintenant, je n'ai pas encore obtenu une seule exception OOM. J'ai testé cela sur l'émulateur, sur mon Nexus One et sur mon Nexus S. J'ai testé des URL d'images contenant des images en qualité HD. Le seul goulot d'étranglement est qu'il prend plus de temps à télécharger.
Il n'y a qu'un seul scénario possible où j'imagine que le MOO apparaîtra, et c'est si nous téléchargeons beaucoup, de très grandes images, et avant qu'elles ne soient mises à l'échelle et mises en cache, prennent simultanément plus de mémoire et provoquent un MOO. Mais ce n'est même pas une situation idéale de toute façon et il ne sera probablement pas possible de résoudre de manière plus réalisable.
Signaler des erreurs dans les commentaires! :-)
la source
J'ai fait ce qui suit pour prendre l'image et la redimensionner à la volée. J'espère que cela t'aides
la source
Il semble que ce soit un problème très long, avec beaucoup d'explications différentes. J'ai suivi les conseils des deux réponses présentées les plus courantes ici, mais aucune de celles-ci n'a résolu mes problèmes de machine virtuelle prétendant qu'elle ne pouvait pas se permettre les octets pour effectuer la partie de décodage du processus. Après avoir creusé, j'ai appris que le vrai problème ici est le processus de décodage qui enlève le tas NATIVE .
Voir ici: BitmapFactory OOM me rend fou
Cela m'a amené à un autre fil de discussion où j'ai trouvé quelques solutions supplémentaires à ce problème. L'une consiste à appeler
System.gc();
manuellement après l'affichage de votre image. Mais cela fait en fait que votre application utilise PLUS de mémoire, dans un effort pour réduire le tas natif. La meilleure solution à partir de la sortie de 2.0 (Donut) est d'utiliser l'option BitmapFactory "inPurgeable". J'ai donc simplement ajoutéo2.inPurgeable=true;
juste aprèso2.inSampleSize=scale;
.Plus d'informations sur ce sujet ici: la limite de la mémoire n'est-elle que de 6 Mo?
Maintenant, après avoir dit tout cela, je suis aussi un cancre complet avec Java et Android. Donc, si vous pensez que c'est une façon terrible de résoudre ce problème, vous avez probablement raison. ;-) Mais cela a fait des merveilles pour moi, et j'ai trouvé impossible d'exécuter la machine virtuelle hors du cache de tas maintenant. Le seul inconvénient que je peux trouver est que vous jetez votre image dessinée en cache. Ce qui signifie que si vous revenez à DROITE sur cette image, vous la redessinez à chaque fois. Dans le cas du fonctionnement de mon application, ce n'est pas vraiment un problème. Votre kilométrage peut varier.
la source
malheureusement, si aucun des éléments ci-dessus ne fonctionne, ajoutez-le à votre fichier manifeste . Balise d' application interne
la source
Utiliser ceci
bitmap.recycle();
Cela aide sans aucun problème de qualité d'image.la source
J'ai une solution beaucoup plus efficace qui n'a besoin d'aucune mise à l'échelle. Décodez simplement votre bitmap une seule fois, puis mettez-le en cache dans une carte par rapport à son nom. Ensuite, récupérez simplement le bitmap par rapport au nom et définissez-le dans ImageView. Il n'y a plus rien à faire.
Cela fonctionnera car les données binaires réelles du bitmap décodé ne sont pas stockées dans le tas VM dalvik. Il est stocké en externe. Ainsi, chaque fois que vous décodez un bitmap, il alloue de la mémoire en dehors du tas VM qui n'est jamais récupéré par GC
Pour vous aider à mieux apprécier cela, imaginez que vous avez conservé votre image dans le dossier dessinable. Vous obtenez simplement l'image en faisant un getResources (). GetDrwable (R.drawable.). Cela ne décode PAS votre image à chaque fois, mais réutilise une instance déjà décodée chaque fois que vous l'appelez. Donc, en substance, il est mis en cache.
Maintenant que votre image est dans un fichier quelque part (ou peut même provenir d'un serveur externe), il est de VOTRE responsabilité de mettre en cache l'instance bitmap décodée pour la réutiliser où elle est nécessaire.
J'espère que cela t'aides.
la source
J'ai résolu le même problème de la manière suivante.
la source
Il y a deux problèmes ici ...
la source
Cela a fonctionné pour moi!
la source
Aucune des réponses ci-dessus n'a fonctionné pour moi, mais j'ai trouvé une solution de contournement horrible qui a résolu le problème. J'ai ajouté une très petite image de 1 x 1 pixel à mon projet en tant que ressource et je l'ai chargée dans mon ImageView avant d'appeler dans la récupération de place. Je pense qu'il se pourrait que l'ImageView ne libère pas le Bitmap, donc GC ne l'a jamais repris. C'est moche, mais ça semble marcher pour l'instant.
la source
bitmap
dans le code ci - dessus est l'image déjà affichée précédente, vous devez le recycler, effacer toute référence à elle, faire l'imageView
oublier et en définissant un petit remplacementgc()
; et après tout cela: chargez votre NOUVELLE imagebitmap
et affichez-la,...
dans le code ci-dessus.Excellentes réponses ici, mais je voulais un cours entièrement utilisable pour résoudre ce problème .. alors j'en ai fait une.
Voici ma classe BitmapHelper qui est à l'épreuve de OutOfMemoryError :-)
la source
Cela fonctionne pour moi.
et c'est sur monodroid C #. vous pouvez facilement changer le chemin de l'image. ce qui importe ici, ce sont les options à définir.
la source
Cela semble être l'endroit approprié pour partager ma classe d'utilité pour le chargement et le traitement d'images avec la communauté, vous êtes invités à l'utiliser et à la modifier librement.
la source
Dans une de mes applications, je dois prendre une photo de
Camera/Gallery
. Si l'utilisateur clique sur l'image de la caméra (peut être 2MP, 5MP ou 8MP), la taille de l'image varie dekB
s àMB
s. Si la taille de l'image est inférieure (ou jusqu'à 1-2 Mo) au-dessus du code, cela fonctionne bien, mais si j'ai une image de taille supérieure à 4 Mo ou 5 Mo, alorsOOM
vient dans le cadre :(alors j'ai travaillé pour résoudre ce problème et enfin j'ai apporté l'amélioration ci-dessous au code de Fedor (All Credit to Fedor pour avoir fait une si belle solution) :)
J'espère que cela aidera les copains confrontés au même problème!
pour plus s'il vous plaît se référer à ceci
la source
Je viens de tomber sur ce problème il y a quelques minutes. Je l'ai résolu en faisant un meilleur travail de gestion de mon adaptateur listview. Je pensais que c'était un problème avec les centaines d'images 50x50px que j'utilisais, il s'avère que j'essayais de gonfler ma vue personnalisée chaque fois que la ligne était affichée. Simplement en testant pour voir si la ligne a été gonflée, j'ai éliminé cette erreur et j'utilise des centaines de bitmaps. Il s'agit en fait d'un Spinner, mais l'adaptateur de base fonctionne tout de même pour un ListView. Cette solution simple a également considérablement amélioré les performances de l'adaptateur.
la source
J'ai passé toute la journée à tester ces solutions et la seule chose qui a fonctionné pour moi est les approches ci-dessus pour obtenir l'image et appeler manuellement le GC, ce que je sais n'est pas censé être nécessaire, mais c'est la seule chose qui a fonctionné lorsque je soumets mon application à des tests de charge élevée pour basculer entre les activités. Mon application a une liste d'images miniatures dans une vue de liste (disons l'activité A) et lorsque vous cliquez sur l'une de ces images, elle vous amène à une autre activité (disons l'activité B) qui montre une image principale pour cet élément. Lorsque je basculais entre les deux activités, j'obtenais finalement l'erreur OOM et l'application se fermait de force.
Lorsque j'arrivais à mi-chemin de la liste, cela plantait.
Maintenant, lorsque j'implémente ce qui suit dans l'activité B, je peux parcourir l'intégralité de la liste sans problème et continuer et continuer et continuer ... et c'est très rapide.
la source
Ce problème se produit uniquement dans les émulateurs Android. J'ai également rencontré ce problème dans un émulateur, mais lorsque j'ai vérifié un appareil, cela a bien fonctionné.
Veuillez donc enregistrer un appareil. Il peut être exécuté dans l'appareil.
la source
Mes 2 cents: j'ai résolu mes erreurs OOM avec des bitmaps en:
a) redimensionner mes images par un facteur 2
b) en utilisant la bibliothèque Picasso dans mon adaptateur personnalisé pour un ListView, avec un appel dans getView comme ceci:
Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);
la source
utilisez ce code pour chaque image dans la sélection de SdCard ou dessiné pour convertir un objet bitmap.
utilisez votre chemin d'image instend ImageData_Path.get (img_pos) .getPath () .
la source
En règle générale, la taille du tas de l'appareil Android n'est que de 16 Mo (varie selon l'appareil / le système d'exploitation, voir les tailles de tas après ), si vous chargez les images et qu'il dépasse la taille de 16 Mo, cela provoquera une exception de mémoire, au lieu d'utiliser le bitmap pour le chargement les images de la carte SD ou des ressources ou même du réseau essaient d'utiliser getImageUri , le chargement du bitmap nécessite plus de mémoire, ou vous pouvez définir bitmap sur null si votre travail est fait avec ce bitmap.
la source
Toutes les solutions ici nécessitent la définition d'un IMAGE_MAX_SIZE. Cela limite les appareils avec un matériel plus puissant et si la taille de l'image est trop faible, elle semble moche sur l'écran HD.
Je suis sorti avec une solution qui fonctionne avec mon Samsung Galaxy S3 et plusieurs autres appareils, y compris des appareils moins puissants, avec une meilleure qualité d'image lorsqu'un appareil plus puissant est utilisé.
L'essentiel est de calculer la mémoire maximale allouée à l'application sur un appareil particulier, puis de définir l'échelle pour qu'elle soit la plus basse possible sans dépasser cette mémoire. Voici le code:
J'ai défini la mémoire maximale utilisée par ce bitmap à 25% de la mémoire maximale allouée, vous devrez peut-être l'ajuster à vos besoins et vous assurer que ce bitmap est nettoyé et ne reste pas en mémoire lorsque vous avez fini de l'utiliser. En règle générale, j'utilise ce code pour effectuer une rotation d'image (bitmap source et destination), mon application doit donc charger 2 bitmaps en mémoire en même temps, et 25% me donne un bon tampon sans manquer de mémoire lors de la rotation d'image.
J'espère que cela aide quelqu'un là-bas ..
la source
Cela
OutofMemoryException
ne peut pas être totalement résolu en appelant leSystem.gc()
etc.En se référant au cycle de vie de l' activitéLes états d'activité sont déterminés par le système d'exploitation lui-même en fonction de l'utilisation de la mémoire pour chaque processus et de la priorité de chaque processus.
Vous pouvez considérer la taille et la résolution de chacune des images bitmap utilisées. Je recommande de réduire la taille, de rééchantillonner à une résolution inférieure, de se référer à la conception des galeries (une petite image PNG et une image originale.)
la source
Ce code aidera à charger une grande image bitmap à partir de drawable
la source
Bitmap.Config.ARGB_565
? Si la haute qualité n'est pas critique.