2012-09-08 15 views
5

Estoy tratando de crear una aplicación que se utiliza para descargar imágenes del servidor y mostrarlas en la vista de lista. El problema que tuve fue la pérdida de memoria y la falla de la aplicación. Estaba buscando en el blog de Android como este link, muestra una gran idea, pero aún no es suficiente para hacerlo con múltiples hilos. Algunos dispositivos de Android pueden funcionar con él, pero algunos dispositivos solo pueden manejarlos en una sola cadena y, a veces, no funcionan en absoluto.Imagen de descarga de Android del servidor y guardar en sdcard sin utilizar BitmapFactory

Mi aplicación tiene muchas actividades y cada una de ellas tiene una vista de lista que necesita mostrar la imagen lo más rápido posible. A través de Google IO 2012 usan buffer para guardar la imagen original en la tarjeta SD y soluciona el problema de memoria de fuga pero hace que la carga sea lenta ya que la imagen que necesita descargar era demasiado grande.

Mi pregunta es: ¿Hay alguna manera de escalar la imagen junto con escribir la imagen en la tarjeta SD? Intuyo que una posible solución es usar Omitir byte en el objeto inputstream y pude encontrar Width and Height también Bit por píxel de la imagen que necesito descargar.

El siguiente código se usó en Google IO 2012 y funciona bien con varios subprocesos, en mi caso tengo 4 subprocesos ejecutándose en segundo plano.

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(); 
    } 
} 

Respuesta

1

1) utilizar el siguiente código antes de sus imágenes para liberar el objeto nativo asociado con este mapa de bits, y borrar la referencia a los datos de píxeles. Simplemente permite que sea basura recolectada si no hay otras referencias.

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

2) utilizar este método para reducir el tamaño del mapa de bits en la memoria:

/** 
* 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

Gracias por su respuesta, ya he pasado por este caso, pero todavía tengo memoria de fuga con múltiples hilos para algunos dispositivos que no permiten que JNI asigne más memoria. El código de Google IO 2012 puede hacer que funcione con múltiples hilos que admitan todos los dispositivos, pero es muy lento en caso de que la imagen sea demasiado grande. De alguna manera, el usuario navega rápidamente por la actividad, por lo que la primera vez que carga, no es nada bueno. – vsatkh

0

Se puede usar esta.

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

Este código de descarga de las imágenes sin necesidad de utilizar la fábrica de mapa de bits, no su trabajo en el emulador, utilice los teléfonos 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> 
Cuestiones relacionadas