Cómo descargar y guardar una imagen en Android

Respuestas:

224

Editar a partir del 30.12.2015: la guía definitiva para la descarga de imágenes


última actualización importante: 31 de marzo de 2016


TL; DR también conocido como deja de hablar, solo dame el código !!

Vaya al final de esta publicación, copie la BasicImageDownloader(versión javadoc aquí ) en su proyecto, implemente la OnImageLoaderListenerinterfaz y listo.

Nota : aunque BasicImageDownloadermaneja posibles errores y evitará que su aplicación se bloquee en caso de que algo salga mal, no realizará ningún procesamiento posterior (por ejemplo, reducción de tamaño) en la descarga Bitmaps.


Dado que esta publicación ha recibido mucha atención, he decidido modificarla por completo para evitar que la gente use tecnologías obsoletas, malas prácticas de programación o simplemente hacer cosas tontas, como buscar "hacks" para ejecutar la red en el hilo principal o aceptar todos los certificados SSL.

Creé un proyecto de demostración llamado "Image Downloader" que demuestra cómo descargar (y guardar) una imagen usando mi propia implementación de descarga, la función de Android integrada y DownloadManageralgunas bibliotecas populares de código abierto. Puede ver el código fuente completo o descargar el proyecto en GitHub .

Nota : Todavía no he ajustado la gestión de permisos para SDK 23+ (Marshmallow), por lo que el proyecto se dirige al SDK 22 (Lollipop).

En mi conclusión al final de esta publicación, compartiré mi humilde opinión sobre el caso de uso adecuado para cada forma particular de descarga de imágenes que he mencionado.

Comencemos con una implementación propia (puedes encontrar el código al final de la publicación). En primer lugar, este es un ImageDownloader básico y eso es todo. Todo lo que hace es conectarse a la URL dada, leer los datos e intentar decodificarlos como un Bitmap, activando las OnImageLoaderListenerdevoluciones de llamada de la interfaz cuando sea apropiado. La ventaja de este enfoque: es simple y tiene una visión general clara de lo que está sucediendo. Un buen camino a seguir si todo lo que necesita es descargar / mostrar y guardar algunas imágenes, mientras que no le importa mantener una memoria / caché de disco.

Nota: en el caso de imágenes grandes, es posible que deba reducirlas .

-

Android DownloadManager es una forma de permitir que el sistema maneje la descarga por usted. De hecho, es capaz de descargar cualquier tipo de archivo, no solo imágenes. Puede permitir que la descarga se realice de forma silenciosa e invisible para el usuario, o puede permitir que el usuario vea la descarga en el área de notificación. También puede registrarse BroadcastReceiverpara recibir una notificación después de que se complete la descarga. La configuración es bastante sencilla, consulte el proyecto vinculado para obtener un código de muestra.

DownloadManagerPor lo general, usar el archivo no es una buena idea si también desea mostrar la imagen, ya que necesitaría leer y decodificar el archivo guardado en lugar de simplemente configurar el descargado Bitmapen un ImageView. El DownloadManagertambién no proporciona ninguna API para que la aplicación para realizar un seguimiento del progreso de la descarga.

-

Ahora, la introducción de las grandes cosas: las bibliotecas. Pueden hacer mucho más que descargar y mostrar imágenes, incluyendo: crear y administrar la memoria / caché del disco, cambiar el tamaño de las imágenes, transformarlas y más.

Comenzaré con Volley , una poderosa biblioteca creada por Google y cubierta por la documentación oficial. Si bien es una biblioteca de redes de uso general que no se especializa en imágenes, Volley presenta una API bastante poderosa para administrar imágenes.

Deberá implementar una clase Singleton para administrar las solicitudes de Volley y estará listo para comenzar.

Es posible que desee reemplazar su ImageViewcon Volley NetworkImageView, por lo que la descarga básicamente se convierte en una sola línea:

((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());

Si necesita más control, así es como se ve al crear un ImageRequestcon Volley:

     ImageRequest imgRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
             @Override
             public void onResponse(Bitmap response) {
                    //do stuff
                }
            }, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, 
             new Response.ErrorListener() {
             @Override
             public void onErrorResponse(VolleyError error) {
                   //do stuff
                }
            });

Vale la pena mencionar que Volley presenta un excelente mecanismo de manejo de errores al proporcionar la VolleyErrorclase que lo ayuda a determinar la causa exacta de un error. Si su aplicación hace muchas redes y la administración de imágenes no es su propósito principal, entonces Volley es la opción perfecta para usted.

-

Picasso de Square es una biblioteca muy conocida que hará todo el proceso de carga de imágenes por usted. Mostrar una imagen con Picasso es tan simple como:

 Picasso.with(myContext)
       .load(url)
       .into(myImageView); 

De forma predeterminada, Picasso administra el caché de memoria / disco, por lo que no debe preocuparse por eso. Para obtener más control, puede implementar la Targetinterfaz y usarla para cargar su imagen; esto proporcionará devoluciones de llamada similares al ejemplo de Volley. Consulte el proyecto de demostración para ver ejemplos.

Picasso también le permite aplicar transformaciones a la imagen descargada e incluso hay otras bibliotecas alrededor que amplían esas API. También funciona muy bien en RecyclerView/ ListView/ GridView.

-

Universal Image Loader es otra biblioteca muy popular que sirve para la gestión de imágenes. Utiliza el suyo propio ImageLoaderque (una vez inicializado) tiene una instancia global que se puede usar para descargar imágenes en una sola línea de código:

  ImageLoader.getInstance().displayImage(url, myImageView);

Si desea realizar un seguimiento del progreso de la descarga o acceder a la descargada Bitmap:

 ImageLoader.getInstance().displayImage(url, myImageView, opts, 
 new ImageLoadingListener() {
     @Override
     public void onLoadingStarted(String imageUri, View view) {
                     //do stuff
                }

      @Override
      public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                   //do stuff
                }

      @Override
      public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                   //do stuff
                }

      @Override
      public void onLoadingCancelled(String imageUri, View view) {
                   //do stuff
                }
            }, new ImageLoadingProgressListener() {
      @Override
      public void onProgressUpdate(String imageUri, View view, int current, int total) {
                   //do stuff
                }
            });

El optsargumento en este ejemplo es un DisplayImageOptionsobjeto. Consulte el proyecto de demostración para obtener más información.

Al igual que Volley, UIL proporciona la FailReasonclase que le permite verificar qué salió mal en caso de falla de descarga. De forma predeterminada, UIL mantiene una memoria / caché de disco si no le indica explícitamente que no lo haga.

Nota : el autor ha mencionado que ya no mantendrá el proyecto a partir del 27 de noviembre de 2015. Pero dado que hay muchos colaboradores, podemos esperar que Universal Image Loader continúe.

-

Fresco de Facebook es la biblioteca más nueva y (IMO) la más avanzada que lleva la administración de imágenes a un nuevo nivel: desde mantenerse Bitmapsalejado del montón de Java (antes de Lollipop) hasta admitir formatos animados y transmisión progresiva de JPEG .

Para obtener más información sobre las ideas y técnicas detrás de Fresco, consulte esta publicación .

El uso básico es bastante simple. Tenga en cuenta que deberá llamar Fresco.initialize(Context);solo una vez, preferiblemente en la Applicationclase. Inicializar Fresco más de una vez puede provocar un comportamiento impredecible y errores OOM.

Fresco usa Drawees para mostrar imágenes, puede pensar en ellas como ImageViews:

    <com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/drawee"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    fresco:fadeDuration="500"
    fresco:actualImageScaleType="centerCrop"
    fresco:placeholderImage="@drawable/placeholder_grey"
    fresco:failureImage="@drawable/error_orange"
    fresco:placeholderImageScaleType="fitCenter"
    fresco:failureImageScaleType="centerInside"
    fresco:retryImageScaleType="centerCrop"
    fresco:progressBarImageScaleType="centerInside"
    fresco:progressBarAutoRotateInterval="1000"
    fresco:roundAsCircle="false" />

Como puede ver, muchas cosas (incluidas las opciones de transformación) ya están definidas en XML, por lo que todo lo que necesita hacer para mostrar una imagen es una sola línea:

 mDrawee.setImageURI(Uri.parse(url));

Fresco proporciona una API de personalización extendida, que, en determinadas circunstancias, puede ser bastante compleja y requiere que el usuario lea los documentos con atención (sí, a veces necesita RTFM).

He incluido ejemplos de imágenes animadas y JPEG progresivos en el proyecto de muestra.


Conclusión: "He aprendido acerca de las grandes cosas, ¿qué debo usar ahora?"

Tenga en cuenta que el siguiente texto refleja mi opinión personal y no debe tomarse como un postulado.

  • Si solo necesita descargar / guardar / mostrar algunas imágenes, no planea usarlas en una Recycler-/Grid-/ListViewy no necesita un montón de imágenes para estar listas para mostrar, BasicImageDownloader debería satisfacer sus necesidades.
  • Si su aplicación guarda imágenes (u otros archivos) como resultado de un usuario o una acción automatizada y no necesita que las imágenes se muestren con frecuencia, use el DownloadManager de Android .
  • En caso de que su aplicación haga muchas redes, transmita / reciba JSONdatos, funcione con imágenes, pero ese no sea el propósito principal de la aplicación, vaya con Volley .
  • Su aplicación está enfocada en imágenes / medios, le gustaría aplicar algunas transformaciones a las imágenes y no quiere molestarse con API complejas: use Picasso (Nota: no proporciona ninguna API para rastrear el estado de descarga intermedio) o Universal Image Cargador
  • Si su aplicación se trata de imágenes, necesita funciones avanzadas como mostrar formatos animados y está listo para leer los documentos, vaya con Fresco .

En caso de que te lo hayas perdido, el enlace de Github para el proyecto de demostración.


Y aqui esta el BasicImageDownloader.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Set;

public class BasicImageDownloader {

    private OnImageLoaderListener mImageLoaderListener;
    private Set<String> mUrlsInProgress = new HashSet<>();
    private final String TAG = this.getClass().getSimpleName();

    public BasicImageDownloader(@NonNull OnImageLoaderListener listener) {
        this.mImageLoaderListener = listener;
    }

    public interface OnImageLoaderListener {
        void onError(ImageError error);      
        void onProgressChange(int percent);
        void onComplete(Bitmap result);
    }


    public void download(@NonNull final String imageUrl, final boolean displayProgress) {
        if (mUrlsInProgress.contains(imageUrl)) {
            Log.w(TAG, "a download for this url is already running, " +
                    "no further download will be started");
            return;
        }

        new AsyncTask<Void, Integer, Bitmap>() {

            private ImageError error;

            @Override
            protected void onPreExecute() {
                mUrlsInProgress.add(imageUrl);
                Log.d(TAG, "starting download");
            }

            @Override
            protected void onCancelled() {
                mUrlsInProgress.remove(imageUrl);
                mImageLoaderListener.onError(error);
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                mImageLoaderListener.onProgressChange(values[0]);
            }

        @Override
        protected Bitmap doInBackground(Void... params) {
            Bitmap bitmap = null;
            HttpURLConnection connection = null;
            InputStream is = null;
            ByteArrayOutputStream out = null;
            try {
                connection = (HttpURLConnection) new URL(imageUrl).openConnection();
                if (displayProgress) {
                    connection.connect();
                    final int length = connection.getContentLength();
                    if (length <= 0) {
                        error = new ImageError("Invalid content length. The URL is probably not pointing to a file")
                                .setErrorCode(ImageError.ERROR_INVALID_FILE);
                        this.cancel(true);
                    }
                    is = new BufferedInputStream(connection.getInputStream(), 8192);
                    out = new ByteArrayOutputStream();
                    byte bytes[] = new byte[8192];
                    int count;
                    long read = 0;
                    while ((count = is.read(bytes)) != -1) {
                        read += count;
                        out.write(bytes, 0, count);
                        publishProgress((int) ((read * 100) / length));
                    }
                    bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
                } else {
                    is = connection.getInputStream();
                    bitmap = BitmapFactory.decodeStream(is);
                }
            } catch (Throwable e) {
                if (!this.isCancelled()) {
                    error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
                    this.cancel(true);
                }
            } finally {
                try {
                    if (connection != null)
                        connection.disconnect();
                    if (out != null) {
                        out.flush();
                        out.close();
                    }
                    if (is != null)
                        is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return bitmap;
        }

            @Override
            protected void onPostExecute(Bitmap result) {
                if (result == null) {
                    Log.e(TAG, "factory returned a null result");
                    mImageLoaderListener.onError(new ImageError("downloaded file could not be decoded as bitmap")
                            .setErrorCode(ImageError.ERROR_DECODE_FAILED));
                } else {
                    Log.d(TAG, "download complete, " + result.getByteCount() +
                            " bytes transferred");
                    mImageLoaderListener.onComplete(result);
                }
                mUrlsInProgress.remove(imageUrl);
                System.gc();
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public interface OnBitmapSaveListener {
        void onBitmapSaved();
        void onBitmapSaveError(ImageError error);
    }


    public static void writeToDisk(@NonNull final File imageFile, @NonNull final Bitmap image,
                               @NonNull final OnBitmapSaveListener listener,
                               @NonNull final Bitmap.CompressFormat format, boolean shouldOverwrite) {

    if (imageFile.isDirectory()) {
        listener.onBitmapSaveError(new ImageError("the specified path points to a directory, " +
                "should be a file").setErrorCode(ImageError.ERROR_IS_DIRECTORY));
        return;
    }

    if (imageFile.exists()) {
        if (!shouldOverwrite) {
            listener.onBitmapSaveError(new ImageError("file already exists, " +
                    "write operation cancelled").setErrorCode(ImageError.ERROR_FILE_EXISTS));
            return;
        } else if (!imageFile.delete()) {
            listener.onBitmapSaveError(new ImageError("could not delete existing file, " +
                    "most likely the write permission was denied")
                    .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
            return;
        }
    }

    File parent = imageFile.getParentFile();
    if (!parent.exists() && !parent.mkdirs()) {
        listener.onBitmapSaveError(new ImageError("could not create parent directory")
                .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
        return;
    }

    try {
        if (!imageFile.createNewFile()) {
            listener.onBitmapSaveError(new ImageError("could not create file")
                    .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
            return;
        }
    } catch (IOException e) {
        listener.onBitmapSaveError(new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION));
        return;
    }

    new AsyncTask<Void, Void, Void>() {

        private ImageError error;

        @Override
        protected Void doInBackground(Void... params) {
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(imageFile);
                image.compress(format, 100, fos);
            } catch (IOException e) {
                error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
                this.cancel(true);
            } finally {
                if (fos != null) {
                    try {
                        fos.flush();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }

        @Override
        protected void onCancelled() {
            listener.onBitmapSaveError(error);
        }

        @Override
        protected void onPostExecute(Void result) {
            listener.onBitmapSaved();
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }

public static Bitmap readFromDisk(@NonNull File imageFile) {
    if (!imageFile.exists() || imageFile.isDirectory()) return null;
    return BitmapFactory.decodeFile(imageFile.getAbsolutePath());
}

public interface OnImageReadListener {
    void onImageRead(Bitmap bitmap);
    void onReadFailed();
}

public static void readFromDiskAsync(@NonNull File imageFile, @NonNull final OnImageReadListener listener) {
    new AsyncTask<String, Void, Bitmap>() {
        @Override
        protected Bitmap doInBackground(String... params) {
            return BitmapFactory.decodeFile(params[0]);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap != null)
                listener.onImageRead(bitmap);
            else
                listener.onReadFailed();
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imageFile.getAbsolutePath());
}

    public static final class ImageError extends Throwable {

        private int errorCode;
        public static final int ERROR_GENERAL_EXCEPTION = -1;
        public static final int ERROR_INVALID_FILE = 0;
        public static final int ERROR_DECODE_FAILED = 1;
        public static final int ERROR_FILE_EXISTS = 2;
        public static final int ERROR_PERMISSION_DENIED = 3;
        public static final int ERROR_IS_DIRECTORY = 4;


        public ImageError(@NonNull String message) {
            super(message);
        }

        public ImageError(@NonNull Throwable error) {
            super(error.getMessage(), error.getCause());
            this.setStackTrace(error.getStackTrace());
        }

        public ImageError setErrorCode(int code) {
            this.errorCode = code;
            return this;
        }

        public int getErrorCode() {
            return errorCode;
        }
      }
   }
Droide
fuente
¿Qué pasa con la devolución de llamada onPictureTaken () que da la imagen como byte [], se puede obtener una URL a esa imagen, directamente desde la cámara? ¿O es outputStream () básico y antiguo la única forma en Android de guardar una imagen que fue tomada por una cámara sin usar la intención incorporada? Eso parece extraño, porque lo natural después de onPictureTaken es, por supuesto, guardarlo. ¿No hay ningún apoyo especial para hacer eso?
Tombola
2
@Tombola ¡Hola! Esta publicación trata sobre la descarga de una imagen de la web. Pero para responder a su pregunta (hasta donde yo la he entendido): la forma común de guardar una imagen de la cámara es obtener su ruta desde Cursor(en el onActivityResult()método) y luego crear una Bitmapusando esa ruta. Y sí, no dejará de usar ay FileOutputStreama ByteArrayOutputStreamsi desea guardar esta imagen en SD.
Droidman
@BartBurg esta pregunta se trata de descargar y guardar una imagen. Pero tiene razón en algún momento, ya que hay un método de escritura, también debería haber un método de lectura en aras de la integridad. Lo agregaré en la próxima actualización de esta publicación pronto.
Droidman
¿Puede proporcionar un ejemplo utilizando este BasicImageDownloader?
Jaydev
1
@JaydevKalivarapu, consulte la aplicación de demostración en GitHub (la clase de origen que contiene el ejemplo )
Droidman
35

Acabo de llegar de resolver este problema y me gustaría compartir el código completo que se puede descargar, guardar en la tarjeta SD (y ocultar el nombre del archivo) y recuperar las imágenes y finalmente verifica si la imagen ya está allí. La URL proviene de la base de datos, por lo que el nombre del archivo puede ser único fácilmente usando id.

primeras imágenes de descarga

   private class GetImages extends AsyncTask<Object, Object, Object> {
    private String requestUrl, imagename_;
    private ImageView view;
    private Bitmap bitmap ; 
      private FileOutputStream fos;
    private GetImages(String requestUrl, ImageView view, String _imagename_) {
        this.requestUrl = requestUrl;
        this.view = view;
        this.imagename_ = _imagename_ ;
    }

    @Override
    protected Object doInBackground(Object... objects) {
        try {
            URL url = new URL(requestUrl);
            URLConnection conn = url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
        } catch (Exception ex) {
        }
        return null;
    }

    @Override
    protected void onPostExecute(Object o) { 
        if(!ImageStorage.checkifImageExists(imagename_))
        { 
                view.setImageBitmap(bitmap);
                ImageStorage.saveToSdCard(bitmap, imagename_); 
            }  
        }  
   }

Luego crea una clase para guardar y recuperar los archivos

  public class ImageStorage {


public static String saveToSdCard(Bitmap bitmap, String filename) {

    String stored = null;

    File sdcard = Environment.getExternalStorageDirectory() ; 

    File folder = new File(sdcard.getAbsoluteFile(), ".your_specific_directory");//the dot makes this directory hidden to the user
    folder.mkdir(); 
    File file = new File(folder.getAbsoluteFile(), filename + ".jpg") ;
    if (file.exists())
        return stored ;

    try {
        FileOutputStream out = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
        stored = "success";
    } catch (Exception e) {
        e.printStackTrace();
    }
     return stored;
   }

public static File getImage(String imagename) {

        File mediaImage = null;
        try {
            String root = Environment.getExternalStorageDirectory().toString();
            File myDir = new File(root);
            if (!myDir.exists())
                return null;

            mediaImage = new File(myDir.getPath() + "/.your_specific_directory/"+imagename);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return mediaImage;
    }
public static boolean checkifImageExists(String imagename)
{
    Bitmap b = null ;
    File file = ImageStorage.getImage("/"+imagename+".jpg");
    String path = file.getAbsolutePath();

    if (path != null)
        b = BitmapFactory.decodeFile(path); 

    if(b == null ||  b.equals(""))
    {
        return false ;
    }
    return true ;
}
  }

Luego, para acceder a las imágenes, primero verifique si ya está allí, si no, luego descargue

          if(ImageStorage.checkifImageExists(imagename))
            {
                File file = ImageStorage.getImage("/"+imagename+".jpg"); 
                String path = file.getAbsolutePath(); 
                if (path != null){
                    b = BitmapFactory.decodeFile(path);
                    imageView.setImageBitmap(b);
                }  
            } else { 
                new GetImages(imgurl, imageView, imagename).execute() ; 
            }
Nasz Njoka Sr.
fuente
Nota : aunque este ejemplo podría funcionar en general, no proporciona ningún manejo de errores y también carece de una comprensión básica deAsyncTask las ventajas (uso adecuado de la parametrización, ejecución en paralelo ...). Consulte mis ejemplos a continuación para obtener más detalles. PS . para aquellos que puedan pensar que escribí esto para promover mi propio código por cualquier motivo: no, solo estoy señalando los problemas que puedo ver en el ejemplo dado.
Droidman
Sí Droidman, estoy de acuerdo contigo. Este fragmento de código debe tomarse como una plantilla y uno tiene que completarlo por su cuenta, incluido el manejo de errores. Por cierto, su código también carece de manejo de errores. ¿Qué pasará con su conexión y transmisiones en caso de IOException?
Androider
@Androider, por favor, mire más de cerca mi download método, particularmente el doInBackgroundmétodo de la tarea que utilizo. An IOExceptionaterrizaría en el catch (Throwable e)bloque, lo que provocaría que ImageErrorse devolviera y onError()se activara la devolución de llamada. El ImageErrorobjeto contendrá el rastro de pila original y la causa de lo ocurridoException
Droidman
1
Sí, pero su conexión no se desconectará y sus transmisiones no se cerrarán
Androider
@Androider ah, veo tu punto. Aunque nunca noté fugas sospechosas en mis dispositivos de prueba, este comportamiento puede ser diferente en otros dispositivos. Gracias por la pista - He actualizado el código
Droidman
32

¿Por qué realmente necesitas tu propio código para descargarlo? ¿Qué tal simplemente pasar su URI al administrador de descargas?

public void downloadFile(String uRl) {
    File direct = new File(Environment.getExternalStorageDirectory()
            + "/AnhsirkDasarp");

    if (!direct.exists()) {
        direct.mkdirs();
    }

    DownloadManager mgr = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);

    Uri downloadUri = Uri.parse(uRl);
    DownloadManager.Request request = new DownloadManager.Request(
            downloadUri);

    request.setAllowedNetworkTypes(
            DownloadManager.Request.NETWORK_WIFI
                    | DownloadManager.Request.NETWORK_MOBILE)
            .setAllowedOverRoaming(false).setTitle("Demo")
            .setDescription("Something useful. No, really.")
            .setDestinationInExternalPublicDir("/AnhsirkDasarp", "fileName.jpg");

    mgr.enqueue(request);

}
AnhSirk Dasarp
fuente
1
Ejemplo perfecto para api> 8.
Jeeten Parmar
¡Tu código funciona perfecto para una imagen! ¿Qué puedo hacer si quiero descargar más (100 imágenes) de mi archivo de imágenes en mi servidor?
Kostantinos Ibra
¡Recibo un mensaje que dice archivo dañado!
Anup
2
Quizás, .setDestinationInExternalPublicDir ("/ AnhsirkDasarp", "fileName.jpg");
Experto quiere ser
2
¿Cómo sabemos si se descargó correctamente o falló?
Prabs
12

podría ayudarte ...

Button download_image = (Button)bigimagedialog.findViewById(R.id.btn_downloadimage);
                    download_image.setOnClickListener(new View.OnClickListener()
                    {
                        public void onClick(View v)
                        {
                            boolean success = (new File("/sdcard/dirname")).mkdir(); 
                            if (!success)
                            {
                                Log.w("directory not created", "directory not created");
                            }

                            try
                            {
                                URL url = new URL("YOUR_URL");
                                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                                connection.setDoInput(true);
                                connection.connect();
                                InputStream input = connection.getInputStream();
                                Bitmap myBitmap = BitmapFactory.decodeStream(input);

                                String data1 = String.valueOf(String.format("/sdcard/dirname/%d.jpg",System.currentTimeMillis()));

                                FileOutputStream stream = new FileOutputStream(data1);

                                ByteArrayOutputStream outstream = new ByteArrayOutputStream();
                                myBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outstream);
                                byte[] byteArray = outstream.toByteArray();

                                stream.write(byteArray);
                                stream.close();

                                Toast.makeText(getApplicationContext(), "Downloading Completed", Toast.LENGTH_SHORT).show();
                            }
                            catch (Exception e)
                            {
                                e.printStackTrace();
                            }
                        }
                    });
Ajay
fuente
6

Tengo una solución simple que está funcionando perfectamente. El código no es mío, lo encontré en este enlace . Estos son los pasos a seguir:

1. Antes de descargar la imagen, escribamos un método para guardar el mapa de bits en un archivo de imagen en el almacenamiento interno de Android. Necesita un contexto, es mejor usar el pase en el contexto de la aplicación mediante getApplicationContext (). Este método se puede volcar en su clase de actividad u otras clases de utilidad.

public void saveImage(Context context, Bitmap b, String imageName) 
{
    FileOutputStream foStream;
    try 
    {
        foStream = context.openFileOutput(imageName, Context.MODE_PRIVATE);
        b.compress(Bitmap.CompressFormat.PNG, 100, foStream);
        foStream.close();
    } 
    catch (Exception e) 
    {
        Log.d("saveImage", "Exception 2, Something went wrong!");
        e.printStackTrace();
    }
}

2. Ahora que tenemos un método para guardar el mapa de bits en un archivo de imagen en andorid, vamos a escribir AsyncTask para descargar imágenes por URL. Esta clase privada debe colocarse en su clase de actividad como una subclase. Después de descargar la imagen, en el método onPostExecute, llama al método saveImage definido anteriormente para guardar la imagen. Tenga en cuenta que el nombre de la imagen está codificado como "my_image.png".

private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
    private String TAG = "DownloadImage";
    private Bitmap downloadImageBitmap(String sUrl) {
        Bitmap bitmap = null;
        try {
            InputStream inputStream = new URL(sUrl).openStream();   // Download Image from URL
            bitmap = BitmapFactory.decodeStream(inputStream);       // Decode Bitmap
            inputStream.close();
        } catch (Exception e) {
            Log.d(TAG, "Exception 1, Something went wrong!");
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        return downloadImageBitmap(params[0]);
    }

    protected void onPostExecute(Bitmap result) {
        saveImage(getApplicationContext(), result, "my_image.png");
    }
}

3. La AsyncTask para descargar la imagen está definida, pero necesitamos ejecutarla para ejecutar esa AsyncTask. Para hacerlo, escriba esta línea en su método onCreate en su clase Activity, o en un método onClick de un botón u otros lugares que considere oportunos.

new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");

La imagen debe guardarse en /data/data/your.app.packagename/files/my_image.jpeg, consulte esta publicación para acceder a este directorio desde su dispositivo.

En mi opinión, esto resuelve el problema. Si desea realizar más pasos, como cargar la imagen, puede seguir estos pasos adicionales:

4. Después de descargar la imagen, necesitamos una forma de cargar el mapa de bits de la imagen desde el almacenamiento interno, para poder usarlo. Escribamos el método para cargar el mapa de bits de la imagen. Este método toma dos parámetros, un contexto y un nombre de archivo de imagen, sin la ruta completa, el context.openFileInput (imageName) buscará el archivo en el directorio de guardado cuando este nombre de archivo se guardó en el método saveImage anterior.

public Bitmap loadImageBitmap(Context context, String imageName) {
    Bitmap bitmap = null;
    FileInputStream fiStream;
    try {
        fiStream    = context.openFileInput(imageName);
        bitmap      = BitmapFactory.decodeStream(fiStream);
        fiStream.close();
    } catch (Exception e) {
        Log.d("saveImage", "Exception 3, Something went wrong!");
        e.printStackTrace();
    }
    return bitmap;
}

5. Ahora tenemos todo lo que necesitamos para configurar la imagen de un ImageView o cualquier otra Vista en la que le guste usar la imagen. Cuando guardamos la imagen, codificamos el nombre de la imagen como "my_image.jpeg", ahora podemos pasar este nombre de imagen al método anterior loadImageBitmap para obtener el mapa de bits y configurarlo como ImageView.

someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));

6. Para obtener la ruta completa de la imagen por nombre de imagen.

File file            = getApplicationContext().getFileStreamPath("my_image.jpeg");
String imageFullPath = file.getAbsolutePath();

7. Compruebe si existe el archivo de imagen.

Archivo archivo =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. Para eliminar el archivo de imagen.

    Archivo archivo = getApplicationContext (). GetFileStreamPath ("my_image.jpeg"); if (file.delete ()) Log.d ("file", "my_image.jpeg eliminado!");

Gláucio Leonardo Sant'ana
fuente
0

este código se ejecuta perfectamente en mi proyecto

downloadImagesToSdCard(imagepath,imagepath);

private void downloadImagesToSdCard(String downloadUrl,String imageName)
        {
            try
            {
                URL url = new URL("www.xxx.com"+downloadUrl); 
                /* making a directory in sdcard */
            //  String sdCard=Environment.getExternalStorageDirectory().toString();
                ContextWrapper cw = new ContextWrapper(getActivity());
                 // path to /data/data/yourapp/app_data/imageDir
                File directory = cw.getDir("files", Context.MODE_PRIVATE);

                File myDir = new File(directory,"folder");

                /*  if specified not exist create new */
                if(!myDir.exists())
                {
                    myDir.mkdir();
                    Log.v("", "inside mkdir");
                }

                /* checks the file and if it already exist delete */
                String fname = imageName;
                File file = new File (myDir, fname);
                Log.d("file===========path", ""+file);
                if (file.exists ()) 
                    file.delete (); 

                /* Open a connection */
                URLConnection ucon = url.openConnection();
                InputStream inputStream = null;
                HttpURLConnection httpConn = (HttpURLConnection)ucon;
                httpConn.setRequestMethod("GET");
                httpConn.connect();
                inputStream = httpConn.getInputStream();
                /*if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) 
                {
                    inputStream = httpConn.getInputStream();
                }*/

                FileOutputStream fos = new FileOutputStream(file);  
                int totalSize = httpConn.getContentLength();
                int downloadedSize = 0;   
                byte[] buffer = new byte[1024];
                int bufferLength = 0;
                while ( (bufferLength = inputStream.read(buffer)) >0 ) 
                {                 
                    fos.write(buffer, 0, bufferLength);                  
                    downloadedSize += bufferLength;                 
                    Log.i("Progress:","downloadedSize:"+downloadedSize+"totalSize:"+ totalSize) ;
                }   

                fos.close();
                Log.d("test", "Image Saved in sdcard..");  
                viewimage();
            }
            catch(IOException io)
            {                  
                io.printStackTrace();
            }
            catch(Exception e)
            {                     
                e.printStackTrace();
            }


        } 

        public void viewimage()
        {
              String path = serialnumber+".png";
               ContextWrapper cw = new ContextWrapper(getActivity());

                //path to /data/data/yourapp/app_data/dirName
                File directory = cw.getDir("files", Context.MODE_PRIVATE);

                File mypath=new File(directory,"folder/"+path);

                Bitmap b;
                try {
                    b = BitmapFactory.decodeStream(new FileInputStream(mypath));
                //  b.compress(format, quality, stream)
                    profile_image.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
tej shah
fuente
1
hola gracias por el aporte. Tenga en cuenta que el enfoque anterior de guardar la imagen en el almacenamiento privado de la aplicación tiene 2 desventajas: 1) la imagen solo estará disponible para su aplicación y 2) debe evitar guardar imágenes en el almacenamiento privado de la aplicación, ya que no está diseñado para contenido grande.
Droidman
0

Prueba esto

 try
                {
                    Bitmap bmp = null;
                    URL url = new URL("Your_URL");
                    URLConnection conn = url.openConnection();
                    bmp = BitmapFactory.decodeStream(conn.getInputStream());
                    File f = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis() + ".jpg");
                    if(f.exists())
                        f.delete();
                    f.createNewFile();
                    Bitmap bitmap = bmp;
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
                    byte[] bitmapdata = bos.toByteArray();
                    FileOutputStream fos = new FileOutputStream(f);
                    fos.write(bitmapdata);
                    fos.flush();
                    fos.close();
                    Log.e(TAG, "imagepath: "+f );
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
Sunil
fuente
0
public class testCrop extends AppCompatActivity {
    ImageView iv;
    String imagePath = "https://style.pk/wp-content/uploads/2015/07/omer-Shahzad-performed-umrah-600x548.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testcrpop);
        iv = (ImageView) findViewById(R.id.testCrop);
        imageDownload image = new imageDownload(testCrop.this, iv);
        image.execute(imagePath);
    }
    class imageDownload extends AsyncTask<String, Integer, Bitmap> {
        Context context;
        ImageView imageView;
        Bitmap bitmap;
        InputStream in = null;
        int responseCode = -1;
//constructor.
        public imageDownload(Context context, ImageView imageView) {
            this.context = context;
            this.imageView = imageView;
        }
        @Override
        protected void onPreExecute() {
        }
        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                URL url = new URL(params[0]);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setDoOutput(true);
                httpURLConnection.connect();
                responseCode = httpURLConnection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    in = httpURLConnection.getInputStream();
                    bitmap = BitmapFactory.decodeStream(in);
                    in.close();
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bitmap;
        }
        @Override
        protected void onPostExecute(Bitmap data) {
            imageView.setImageBitmap(data);
            saveImage(data);
        }

        private void saveImage(Bitmap data) {
            File createFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"test");
            createFolder.mkdir();
            File saveImage = new File(createFolder,"downloadimage.jpg");
            try {
                OutputStream outputStream = new FileOutputStream(saveImage);
                data.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
                outputStream.flush();
                outputStream.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

SALIDAingrese la descripción de la imagen aquí

Asegúrese de haber agregado permiso para escribir datos en la memoria

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Shahzad Afridi
fuente