2012-09-08 1 views
5

J'essaie de créer une application qui permet de télécharger l'image du serveur et de l'afficher dans la liste. Le problème que j'ai fait était la fuite de la mémoire et faire planter mon application. Je cherchais sur un blog Android tel que celui-ci link, ça montre une super idée mais ce n'est pas encore assez pour le faire avec plusieurs threads. Certains appareils Android peuvent fonctionner avec lui, mais certains appareils ne peuvent gérer que dans un seul thread et parfois, il ne peut pas fonctionner du tout.Android télécharger l'image à partir du serveur et enregistrer sur la carte SD sans utiliser BitmapFactory

Mon application a beaucoup d'activité et chacune d'elles a une Listview qui doit afficher une image aussi vite que possible. Grâce à Google IO 2012, ils utilisent un tampon pour enregistrer l'image originale sur la carte SD et résoudre le problème de mémoire de fuite, mais cela rend le chargement si lent puisque l'image à télécharger était trop grande.

Ma question est: Existe-t-il un moyen de mettre l'image à l'échelle en même temps que d'écrire une image sur la carte SD? Je trouve une solution possible est d'utiliser Skip octet dans l'objet inputtream et j'ai pu trouver Largeur et Hauteur aussi Bit par pixel de l'image que j'ai besoin de télécharger.

Le code suivant a été utilisé dans Google IO 2012 et il fonctionne bien avec plusieurs threads, dans mon cas, j'ai 4 threads en arrière-plan.

private void downloadAndWriteFile(final String url, final File file) throws OutOfMemoryError { 
    BufferedOutputStream out = null; 

    try { 
     HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); 
     conn.setDoInput(true); 
     conn.connect(); 

     final InputStream in = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE_BYTES); // buffer size 1KB 
     out = new BufferedOutputStream(new FileOutputStream(file), IO_BUFFER_SIZE_BYTES); 

     int b; 
     while ((b = in.read()) != -1) { 
      out.write(b); 
     } 
     out.close(); 
     conn.disconnect(); 
    } 
    catch (Exception e) { 
     Log.e(TAG, "!!downloadAndWriteFile " + e.getMessage()); 
     file.delete(); 
    } 
} 

Répondre

1

1) utilisez le code suivant avant de vos images pour libérer l'objet natif associé à ce bitmap et désactivez la référence aux données de pixels. Cela lui permet simplement d'être collecté s'il n'y a pas d'autres références.

BitmapDrawable drawable = (BitmapDrawable) myImage.getDrawable(); 
Bitmap bitmap = drawable.getBitmap(); 
if (bitmap != null) 
{ 
    bitmap.recycle(); 
} 

2) utiliser cette méthode pour réduire la taille de bitmap dans la mémoire:

/** 
* decodes image and scales it to reduce memory consumption 
* 
* @param file 
* @param requiredSize 
* @return 
*/ 
public static Bitmap decodeFile(File file, int requiredSize) { 
    try { 

     // Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     BitmapFactory.decodeStream(new FileInputStream(file), null, o); 

     // The new size we want to scale to 

     // Find the correct scale value. It should be the power of 2. 
     int width_tmp = o.outWidth, height_tmp = o.outHeight; 
     int scale = 1; 
     while (true) { 
      if (width_tmp/2 < requiredSize 
        || height_tmp/2 < requiredSize) 
       break; 
      width_tmp /= 2; 
      height_tmp /= 2; 
      scale *= 2; 
     } 

     // Decode with inSampleSize 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = scale; 

     Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file), 
       null, o2); 

     return bmp; 

    } catch (FileNotFoundException e) { 
    } finally { 
     System.gc(); 
    } 
    return null; 
} 
+0

Merci pour votre réponse, j'étais déjà à travers ce cas, mais il y a toujours une mémoire de fuite avec plusieurs threads pour certains périphériques qui ne permettent pas à JNI d'allouer plus de mémoire. Le code de Google IO 2012 peut le faire fonctionner avec plusieurs threads qui supportent tous les périphériques, mais il est si lent au cas où l'image est trop grande. D'une manière ou d'une autre, l'utilisateur navigue rapidement, donc lors du premier chargement, ce n'est pas bon du tout. – vsatkh

0

Vous pouvez utiliser ce produit.

private void downloadImagesToSdCard(String downloadUrl,String imageName) { 
try { 
    URL url = new URL(downloadUrl); //you can write here any link 

    File myDir = new File("/sdcard"+"/"+Constants.imageFolder); 
    //Something like ("/sdcard/file.mp3") 


    if (!myDir.exists()) { 
     myDir.mkdir(); 
     Log.v("", "inside mkdir"); 

    } 

    Random generator = new Random(); 
    int n = 10000; 
    n = generator.nextInt(n); 
    String fname = imageName; 
    File file = new File (myDir, fname); 
    if (file.exists()) file.delete(); 

     /* Open a connection to that URL. */ 
     URLConnection ucon = url.openConnection(); 
     InputStream inputStream = null; 
     HttpURLConnection httpConn = (HttpURLConnection)ucon; 
     httpConn.setRequestMethod("GET"); 
     httpConn.connect(); 

     if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) { 
     inputStream = httpConn.getInputStream(); 
     } 

     /* 
     * Define InputStreams to read from the URLConnection. 
     */ 
     // InputStream is = ucon.getInputStream(); 
     /* 
     * Read bytes to the Buffer until there is nothing more to read(-1). 
     */ 

     FileOutputStream fos = new FileOutputStream(file); 
     int size = 1024*1024; 
     byte[] buf = new byte[size]; 
     int byteRead; 
     while (((byteRead = inputStream.read(buf)) != -1)) { 
      fos.write(buf, 0, byteRead); 
      bytesDownloaded += byteRead; 
     } 
     /* Convert the Bytes read to a String. */ 

     fos.close(); 

} catch(IOException io) { 
    networkException = true; 
    continueRestore = false; 
} catch(Exception e) { 
    continueRestore = false; 
    e.printStackTrace(); 
} 

}

0

Ce code télécharger les images sans usine bitmap, sa ne fonctionne pas dans l'émulateur, utilisez tous les téléphones Android

package com.example.filedownload; 


import org.apache.http.util.ByteArrayBuffer; 

import android.os.Bundle; 
import android.app.Activity; 
import android.util.Log; 
import android.view.Menu; 
import android.view.View; 
import android.widget.Button; 
import android.content.*; 
import android.app.*; 
import android.net.*; 
import android.app.DownloadManager.Request; 
import android.os.Environment; 
public class MainActivity extends Activity { 
    public long reference; 
    BroadcastReceiver receiver; 
    @Override 
     protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 


     Button button=(Button)findViewById(R.id.button1); 
       button.setOnClickListener(new View.OnClickListener() { 
       public void onClick(View v) { 


           String file = "http://tmacfitness.com/wp-content/uploads/2013/04/Beauty-of-nature-random-4884759-1280-800.jpg"; 
           String serviceString = Context.DOWNLOAD_SERVICE; 
           DownloadManager downloadManager; 
           downloadManager = (DownloadManager)getSystemService(serviceString); 
           Uri uri = Uri.parse(file); 
           DownloadManager.Request request ; 
           request = new Request(uri); 
           request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "accel.jpg"); 
           reference = downloadManager.enqueue(request); 



       } 

     }); 

     IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); 
     receiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
     long ref = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); 
     if (reference == ref) { 
     setContentView(R.layout.finalscreen); 
     unregister(); 
     } 
     } 
     }; 
     registerReceiver(receiver, filter); 
    } 
     public void unregister(){ 
      unregisterReceiver(receiver); 

    } 
} 

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".MainActivity" > 

    <TableLayout 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentTop="true" > 

     <TableRow 
      android:id="@+id/tableRow1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 
     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow2" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 

      <CheckedTextView 
       android:id="@+id/checkedTextView1" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Accel" /> 

     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow3" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 

      <Button 
       android:id="@+id/button1" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Button" /> 

     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow4" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 
     </TableRow> 
    </TableLayout> 

</RelativeLayout> 

finalscreen .xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="270dp" 
     android:layout_height="wrap_content" 
     android:layout_weight="2.12" 
     android:text="DOWNLOAD COMPLETED" /> 

</LinearLayout> 
Questions connexes