IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Gestion image et fuite mémoire


Sujet :

Android

  1. #1
    Jay
    Jay est déconnecté
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2002
    Messages : 124
    Par défaut Gestion image et fuite mémoire
    Bonjour,

    Je développe actuellement une application qui gère l'affichage de plusieurs image provenant du téléphone ou d'internet.

    Mon problème c'est que de temps en temps sans vraiment l'expliquer, l'application "Crash" avec un message du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    "java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    	at android.graphics.Bitmap.nativeCreate(Native Method)
    	at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
    Existe-t-il un moyen d'analyser les fuites mémoires ou les ressources non utilisées.

    Merci

  2. #2
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Salut,

    Ton problème vient d'un non recycle sur une bitmap.

    Il faut les recycler.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // désalloue ta mémoire
    bitmap.recycle();
    Attention celle présente dans les imageview aussi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    ImageView iv = findViewbyId(R.id.ton imageview);
    BitmapDrawable dw = (BitmapDrawable) iv.getDrawable();
    		if (dw != null) {
    			Bitmap bmpold = dw.getBitmap();
    			if (bmpold != null)
    				bmpold.recycle();
    		}
    Pour voir ta Mémoire,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public static void logHeap(Class clazz) {
        Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));
        Double available = new Double(Debug.getNativeHeapSize())/1048576.0);
        Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0);
        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(2);
        df.setMinimumFractionDigits(2);
     
        Log.d(APP, "debug. =================================");
        Log.d(APP, "debug.heap native: allocated " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free) in [" + clazz.getName().replaceAll("com.myapp.android.","") + "]");
        Log.d(APP, "debug.memory: allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)");
        System.gc();
        System.gc();
     
        // don't need to add the following lines, it's just an app specific handling in my app        
        if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }

  3. #3
    Jay
    Jay est déconnecté
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2002
    Messages : 124
    Par défaut
    Merci pour la réponse aussi rapide.

    Je regarde cela et je fais mes tests dans l’après midi.

    Il ne me reste plus que ce point avant de mettre l'application sur le Market ;-)

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Salut, j'ai ce souci aussi, je télécharge des photos du net que je stocke sur la carte SD.
    Ensuite j'aimerais les afficher dans une gridView.
    J'ai essayé la technique du recyclage mais cela me donne une nouvelle erreur : java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
    Ce qui semble logique.
    Alors comment faire ?
    De plus, j'ai l'erreur de dépassement de mémoire alors que je ne charge qu'une seul image d'a peine 500 ko !

  5. #5
    Rédacteur
    Avatar de MrDuChnok
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2002
    Messages
    2 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 112
    Par défaut
    Il faut "recycler" une image à partir du moment où elle n'est plus utilisée.

    Pourrais tu nous montrer un peu de code afin d'analyser comment tu charges/utilises/décharges ton image ?

    Merci.

  6. #6
    Membre chevronné
    Avatar de ZouBi
    Inscrit en
    Octobre 2007
    Messages
    508
    Détails du profil
    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 508
    Par défaut
    Citation Envoyé par dawadam Voir le message
    Salut, j'ai ce souci aussi, je télécharge des photos du net que je stocke sur la carte SD.
    Ensuite j'aimerais les afficher dans une gridView.
    J'ai essayé la technique du recyclage mais cela me donne une nouvelle erreur : java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
    Ce qui semble logique.
    Alors comment faire ?
    De plus, j'ai l'erreur de dépassement de mémoire alors que je ne charge qu'une seul image d'a peine 500 ko !
    Est ce que, dans la vrai vie, tu utilises tes objets après les avoir recyclés, ou avant?

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Citation Envoyé par MrDuChnok Voir le message
    Il faut "recycler" une image à partir du moment où elle n'est plus utilisée.

    Pourrais tu nous montrer un peu de code afin d'analyser comment tu charges/utilises/décharges ton image ?

    Merci.
    Je viens de tester avec un code très épuré et ça marche...
    Ça bug quant j'utilise un Adapter pour une GridView.
    Je posterais un code plus approprié dès que possible.


    Citation Envoyé par ZouBi Voir le message
    Est ce que, dans la vrai vie, tu utilises tes objets après les avoir recyclés, ou avant?
    Tu vois, c'est pour ça que j'ai mis que ça semblait logique...

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Voici un joli code qui plante

    Activity :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class TestLoad2 extends Activity {
     
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		this.setContentView(R.layout.menu_gridview);
    		// Adapter
    		AdaptTest adapt = new AdaptTest(this);
    		// GridView
    		GridView gridview = (GridView) findViewById(R.id.gridview);
    		gridview.setAdapter(adapt);
    	}
    }
    Adapter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    public class AdaptTest extends BaseAdapter {
    	private Context context;
     
    	public AdaptTest(Context c) {
    		context = c;
    	}
     
    	public int getCount() {
    		return 1;
    	}
     
    	public Object getItem(int position) {
    		return null;
    	}
     
    	public long getItemId(int position) {
    		return 0;
    	}
     
    	// retourne la view affichée
    	public View getView(int position, View convertView, ViewGroup parent) {
    		ImageView imageView;
    		if (convertView == null) {
    			imageView = new ImageView(context);
    			imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
    			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    			imageView.setPadding(8, 8, 8, 8);
    		} else {
    			imageView = (ImageView) convertView;
    		}
     
    		try {
    			String fileName = "test.jpg";
    			String chemin = Environment.getExternalStorageDirectory()
    					+ "/photos/" + fileName;
    			FileInputStream in = new FileInputStream(chemin);
    			BufferedInputStream buf = new BufferedInputStream(in);
    			Bitmap bmp = BitmapFactory.decodeStream(buf);
    			imageView.setImageDrawable(new BitmapDrawable(bmp));
     
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
     
    		return imageView;
    	}
    }
    GridView :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    <?xml version="1.0" encoding="utf-8"?>
    <GridView xmlns:android="http://schemas.android.com/apk/res/android" 
        android:id="@+id/gridview"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:columnWidth="90dp"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="columnWidth"
        android:gravity="center"
    />
    C'est la ligne :
    Bitmap bmp = BitmapFactory.decodeStream(buf);
    Qui cause l'erreur :
    java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    Une idée ?

  9. #9
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Bonjour,

    Bitmap bmp = BitmapFactory.decodeStream(buf);
    Qui cause l'erreur :
    java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    Les images que tu essayes de charger est trop grande pour la mémoire.

    Essayes de réduire la taille des images soit directement , soit via un scale avant de la positionner dans l'imageview.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Citation Envoyé par Feanorin Voir le message
    Les images que tu essayes de charger est trop grande pour la mémoire.
    Si c'est ça, pourquoi cela fonctionne quand je la charge simplement dans une ImageView ?

    En plus de cela, l'erreur survient à la création de la bitmap, je ne peux donc pas la redimensionner.

  11. #11
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Si c'est ça, pourquoi cela fonctionne quant je la charge simplement dans une ImageView ?

    Les images que tu essayes de charger sont trop grande pour la mémoire.

    N'oublie pas que tu as une GridView qui garde en mémoire toutes les images que tu affiches . Tu n'en as pas qu'une en mémoire .

    Fais un scale à ce moment cela te permettra de réduire la mémoire de chaque image donc de les afficher .

    Après fais bien attention à recycler les images .

    Pour connaître la mémoire utilisé par ton application :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));
    	    Double available = new Double(Debug.getNativeHeapSize())/new Double((1048576));
    	    Double free = new Double(Debug.getNativeHeapFreeSize())/new Double((1048576));
    	    DecimalFormat df = new DecimalFormat();
    	    df.setMaximumFractionDigits(2);
    	    df.setMinimumFractionDigits(2);

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Citation Envoyé par Feanorin Voir le message
    N'oublie pas que tu as une GridView qui garde en mémoire toutes les images que tu affiches . Tu n'en as pas qu'une en mémoire .
    Je fait le test avec une seul image pour le moment et ça plante.
    En plus de ça, quand je met la photo dans les ressources et que je charge la view avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    imageView.setImageResource(R.drawable.photo);
    À la place de charger la bitmap, ça fonctionne !

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    334
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 334
    Par défaut
    Bon, j'ai remarqué que la méthode getView de l'Adapter était appelée 4 fois, même avec une seul photo...

    Alors en utilisant un redimentionnement et en recyclant l'image, ça marche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Bitmap bmp = loadBitmap("photo.jpg");
    imageView.setImageDrawable(new BitmapDrawable(changeTaille(bmp)));
    bmp.recycle();
    Merci !

  14. #14
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 322
    Par défaut
    Bonjour je me permet de ré-ouvrir ce sujet, car j'ai quelques questions et problèmes dessus.
    Je voulais faire une galerie d'image provenant du web (comme le tuto proposé sur le site). Mon problème c'est que les images sont très grosses (je peux en afficher qu'une à la fois). Ce que je fais c'est qu'au début je télécharge les images une par une, je les rétrécie beaucoup et les stockes dans une liste. Je peux donc afficher la banderole du bas.
    Quand je clique sur une image de la banderole je vais chercher sur internet l'image en taille réelle pour avoir une bonne qualité.

    J'ai utilisé le code de Feanorin pour afficher l'espace mémoire de mon application en entrant dans mon activité, à chaque téléchargement et à la destruction de mon activité. J'obtiens des valeurs bizarres :
    En entrant :
    allocated: 9,37
    available: 9,44
    free: 0,08
    Je me dis que j'ai pas énormément d'espace...
    Après le téléchargement des petites images j'obtiens ceci :
    allocated: 10,69
    available: 10,89
    free: 0,18
    Ca augmente légèrement.
    et après le téléchargement d'une grosse image :
    allocated: 25,89
    available: 26,14
    free: 0,25
    et quand je détruis mon activité :
    allocated: 9,44
    available: 26,14
    free: 0,25
    Alors là je comprends plus rien. Pourquoi mon espace augmente. Enfin je vais pas me plaindre, ca me permet de télécharger mes images. Mais si j'en télécharge un autre j'ai l'erreur outOfMemorryError (logique).
    Est ce que vous savez d'où vient cette attitude, est ce normal, comment cela fonctionne t-il exactement ?

    Après j'ai un autre problème
    Dans ma classe j'ai une Bitmap qui contient l'image de mon ImageView.
    Le téléchargement de la première image se passe très bien mais lors de la seconde, j'ai l'erreur de mémoire. Pourtant je stocke ma nouvelle image sur l'ancienne Bitmap. J'ai bien tenté un recycle, mais j'obtiens une autre erreur.
    Voici le code que j'utilise (assez banal) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    URLConnection conn = myURL.openConnection();
    conn.connect();
    InputStream is = conn.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(is);
    currentPicture = BitmapFactory.decodeStream(bis);
    bis.close();
    is.close();
    Si vous avez une idée pour m'aider à résoudre ce problème, je serai ravi de l'entendre.
    Merci d'avance

  15. #15
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Bonjour,

    Le téléchargement de la première image se passe très bien mais lors de la seconde, j'ai l'erreur de mémoire. Pourtant je stocke ma nouvelle image sur l'ancienne Bitmap. J'ai bien tenté un recycle, mais j'obtiens une autre erreur.
    Ton problème provient bien de là , tu as des bitmaps que tu n'as pas libérées.

    Essaye de voir avec l'allocation que tu as utilisé pour savoir où tu as une fuite .

    Pour information le recyclage d'image se fait lorsque tu remplace une bitmap par une autre il faut d'abord libéré l'espace mémoire prise par la première cela se fait comme tel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ImageView iv = findViewbyId(R.id.ton imageview);
    BitmapDrawable dw = (BitmapDrawable) iv.getDrawable();
    		if (dw != null) {
    			Bitmap bmpold = dw.getBitmap();
    			if (bmpold != null)
    				bmpold.recycle();
    		}
    Alors là je comprends plus rien. Pourquoi mon espace augmente. Enfin je vais pas me plaindre, ca me permet de télécharger mes images. Mais si j'en télécharge un autre j'ai l'erreur outOfMemorryError (logique).
    Est ce que vous savez d'où vient cette attitude, est ce normal, comment cela fonctionne t-il exactement ?
    Ton espace augmente car tu demandes à ton application plus d'espace mémoire (heap).

    Essaye aussi de recycler les bitmap que tu alloues dans une procédure sans les réutiliser par la suite (Bitmap temporaire) .

  16. #16
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 322
    Par défaut
    Citation Envoyé par Feanorin Voir le message
    Ton problème provient bien de là , tu as des bitmaps que tu n'as pas libérées.

    Essaye de voir avec l'allocation que tu as utilisé pour savoir où tu as une fuite .

    Pour information le recyclage d'image se fait lorsque tu remplace une bitmap par une autre il faut d'abord libéré l'espace mémoire prise par la première cela se fait comme tel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ImageView iv = findViewbyId(R.id.ton imageview);
    BitmapDrawable dw = (BitmapDrawable) iv.getDrawable();
    		if (dw != null) {
    			Bitmap bmpold = dw.getBitmap();
    			if (bmpold != null)
    				bmpold.recycle();
    		}
    Ok, je pensais que si on écrasait les données, on avait pas besoin de recycler l'ancienne bitmap.
    J'ai appliqué ton code mais je me retrouve avec l'erreur que j'avais déjà eu auparavant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683): FATAL EXCEPTION: main
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@40599770
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.graphics.Canvas.throwIfRecycled(Canvas.java:955)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.graphics.Canvas.drawBitmap(Canvas.java:1044)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:325)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.widget.ImageView.onDraw(ImageView.java:872)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.View.draw(View.java:6880)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.View.draw(View.java:6883)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.widget.FrameLayout.draw(FrameLayout.java:357)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.View.draw(View.java:6883)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.widget.FrameLayout.draw(FrameLayout.java:357)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1862)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewRoot.draw(ViewRoot.java:1522)
    05-10 16:49:54.750: ERROR/AndroidRuntime(19683):     at android.view.ViewRoot.performTraversals(ViewRoot.java:1258)
    Voici comment je l'ai implémenté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    BitmapDrawable dw = (BitmapDrawable) myImageView.getDrawable();
    if (dw != null) {
    	Bitmap b = dw.getBitmap();
    	if (b != null)
    		b.recycle();
    }
    URLConnection conn = myURL.openConnection();
    conn.connect();
    InputStream is = conn.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(is);
    currentPicture = BitmapFactory.decodeStream(bis);
    bis.close();
    is.close();
    Vu que je fais cette opération dans un thread le myImageView.SetImage(currentPicture) est dans le handler.

    J'ai bien essayé de gruger en mettant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if(myImageView.getDrawingCache() != null)
    				myImageView.getDrawingCache().recycle();
    pour éviter l'erreur mais là c'est pire ça ne recycle pas l'image ^^

    En tout cas merci d'essayer de m'aider


    Citation Envoyé par Feanorin Voir le message
    Essaye aussi de recycler les bitmap que tu alloues dans une procédure sans les réutiliser par la suite (Bitmap temporaire) .
    Merci pour le conseil, je vais essayer de le faire partout et pas juste sur le onDestroy();

  17. #17
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Je n'avais pas trouvé cela évident non plus quand il fallait l'implémenter . Mais en tout cas c'est bien ce qui faut faire . Tu ne dois pas le mettre au bon endroit , personnellement je nettoie le cache de mon ImageView juste avant de mettre une nouvelle bitmap.

    Pour les Bitmap temporaire je les force à se recycler à la fin de la procédure .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    BitmapDrawable dw = (BitmapDrawable) myImageView.getDrawable();
    if (dw != null) {
    	Bitmap b = dw.getBitmap();
    	if (b != null)
    		b.recycle();
    }
    URLConnection conn = myURL.openConnection();
    conn.connect();
    InputStream is = conn.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(is);
    currentPicture = BitmapFactory.decodeStream(bis);
    bis.close();
    is.close();
    Par exemple ne fais pas le recyclage ici fais le juste avant ton myImageView.SetImage(currentPicture) je pense que cela reste le meilleur endroit. Ton Handler est dans l' UIThread ?

    Citation:
    Envoyé par Feanorin Voir le message
    Essaye aussi de recycler les bitmap que tu alloues dans une procédure sans les réutiliser par la suite (Bitmap temporaire) .
    Merci pour le conseil, je vais essayer de le faire partout et pas juste sur le onDestroy();
    Juste une nouvelle petite précision , ne recycle pas celle que tu utilises dans les imageview sinon tu perdras également les données dans l'imageview également, ne la recycle que lorsque l'imageview n'en a plus besoin .

    Je te passe le lien de la doc on sait jamais
    http://developer.android.com/referen...#recycle%28%29

  18. #18
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 322
    Par défaut
    Oui j'ai mon Handler dans mon UIthread, pourquoi il ne faut pas faire comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class monActivité extends Activity {
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
    ...
    }
     
    final Handler mHandler = new Handler() {
    ...
    }
     
    }
    Ok je vais essayer de le mettre juste avant de changer la Bitmap. Suis je obligé de passé par un Drawable ou est ce que je peux directement utiliser le getDrawingCache qui me renvoie une Bitmap ? (enfin c'est pas vraiment important, ca rajoute pas beaucoup de ligne de codes ^^).

    Je vais tester ce que tu m'as dit et je re-poste (ça sera surement demain )

    Merci encore pour ton aide

    Edit : je retire ce que j'ai dit sur le getDrawingCache, je n'avais pas lu en entier

  19. #19
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Oui j'ai mon Handler dans mon UIthread, pourquoi il ne faut pas faire comme ça ?
    En fait la partie de ton code qui sera dans l'handler ne sera pas dans l'UIThread , pour remédier à ce problème on passe par un postinvalide sur les objets ou par un RunOnUiThread , et une autre méthode pour pouvoir modifier le graphique. (désolé je n'ai plus la troisième méthode en tête )

    http://developer.android.com/referen...0int,%20int%29

    http://developer.android.com/referen...ng.Runnable%29

    Après je ne sais pas si cela influence ou pas le Recycle mais cela peut être également une piste.

    NB:
    UIThread est le thread qui s'occupe des ressources ce n'est pas parce que ton code est dans l'Activity que celui-ci fait partie de l'UIThread .


    Edit : je retire ce que j'ai dit sur le getDrawingCache, je n'avais pas lu en entier
    .

  20. #20
    Membre chevronné
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    322
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 322
    Par défaut
    Bonjour,

    Ouah j'ai l'impression de ne plus rien comprendre (deux mois sur Android pour rien ^^).

    Citation Envoyé par Feanorin Voir le message
    NB:
    UIThread est le thread qui s'occupe des ressources ce n'est pas parce que ton code est dans l'Activity que celui-ci fait partie de l'UIThread .
    Mais il y a bien que l'UIThread qui peut modifie les éléments de la vue ? Normalement si j'essaye de changer un élément contenu dans ma view depuis un autre thread, je devrai recevoir une erreur de ce type là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    non ? Je pensais que le Handler était une sorte d'observer qui faisait la liaison entre l'UIThread et les autres Thread et donc que son code était plus ou moins rattaché à celui de l'UIThread.

    L'utilisation de la fonction runOnUiThread se fait directement dans le thread
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Thread mTread = new Thread(new Runnable() {
    	@Override
    	public void run() {
    		//Récupération sur internet de l'image
    		runOnUiThread(new Runnable() {
        			public void run() {
          				 //mettre à jour l'écran
       			 }
    		});
    		...
    oui alors je le fais dans le Handler ? Si c'est la première solution est la bonne, les Handler ne servent à rien au final s'ils ne peuvent pas interagir sur la vue.

    Par contre j'ai un plus de mal à voir l'utilisation de invalidate(), postInvalidate(). D'après ce que j'ai compris, on surcharge la méthode invalidate pour qu'elle fasse ce que l'on veut et après on fait myImageView.postInvalidate(); pour appeler la méthode. Je ne vois pas la différence qu'il y a entre les 2 méthodes.

    Désolé et merci de m'avoir consacré de ton temps pour m'expliquer ceci.


    Sinon j'ai fait le test ce matin. Effectivement ca marche bien mieux quand je recycle l'image juste avant d'insérer la nouvelle, sauf dans le cas ou ce sont de très grande image... En effet il n'y a pas la place pour deux images sur la mémoire de l'application. Je vais être obligé de recycler mon image avant de télécharger la nouvelle.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Gestion images opencv python par mémoire partagée
    Par Tchef dans le forum Bibliothèques tierces
    Réponses: 0
    Dernier message: 12/08/2009, 15h12
  2. [tomcat][memoire] java.net.URL et fuite mémoire
    Par Seiya dans le forum Tomcat et TomEE
    Réponses: 6
    Dernier message: 09/03/2009, 10h41
  3. Réponses: 2
    Dernier message: 27/12/2004, 09h23
  4. [SWT]SWT et fuite mémoire(ou pas)
    Par menuge dans le forum SWT/JFace
    Réponses: 2
    Dernier message: 22/06/2004, 21h40
  5. [debug] fuites mémoires
    Par tmonjalo dans le forum C
    Réponses: 3
    Dernier message: 28/07/2003, 17h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo