Come scaricare e salvare un'immagine su Android


Risposte:


224

Modifica a partire dal 30.12.2015 - La guida definitiva al download di immagini


ultimo importante aggiornamento: 31 marzo 2016


TL; DR aka smettila di parlare, dammi solo il codice !!

Salta alla fine di questo post, copia la BasicImageDownloader(versione javadoc qui ) nel tuo progetto, implementa l' OnImageLoaderListenerinterfaccia e il gioco è fatto.

Nota : sebbene BasicImageDownloadergestisca possibili errori e impedirà alla tua app di bloccarsi nel caso in cui qualcosa vada storto, non eseguirà alcuna post-elaborazione (es. Ridimensionamento) sul file scaricato Bitmaps.


Dato che questo post ha ricevuto molta attenzione, ho deciso di rielaborarlo completamente per impedire alla gente di utilizzare tecnologie deprecate, cattive pratiche di programmazione o semplicemente fare cose stupide - come cercare "hack" per eseguire la rete sul thread principale o accetta tutti i certificati SSL.

Ho creato un progetto demo chiamato "Image Downloader" che dimostra come scaricare (e salvare) un'immagine utilizzando la mia implementazione del downloader, il built-in di Android DownloadManagere alcune popolari librerie open source. Puoi visualizzare il codice sorgente completo o scaricare il progetto su GitHub .

Nota : non ho ancora modificato la gestione delle autorizzazioni per SDK 23+ (Marshmallow), quindi il progetto ha come target l'SDK 22 (Lollipop).

Nella mia conclusione alla fine di questo post condividerò la mia modesta opinione sul caso d'uso appropriato per ogni particolare modo di scaricare le immagini che ho menzionato.

Cominciamo con una propria implementazione (puoi trovare il codice alla fine del post). Prima di tutto, questo è un ImageDownloader di base e basta. Tutto ciò che fa è connettersi all'URL fornito, leggere i dati e provare a decodificarli come un Bitmap, attivando i OnImageLoaderListenercallback dell'interfaccia quando appropriato. Il vantaggio di questo approccio: è semplice e hai una chiara panoramica di cosa sta succedendo. Un buon modo se tutto ciò di cui hai bisogno è scaricare / visualizzare e salvare alcune immagini, mentre non ti interessa mantenere una memoria / cache del disco.

Nota: in caso di immagini di grandi dimensioni, potrebbe essere necessario ridimensionarle .

-

Android DownloadManager è un modo per consentire al sistema di gestire il download per te. In realtà è in grado di scaricare qualsiasi tipo di file, non solo immagini. Puoi lasciare che il download avvenga in modo silenzioso e invisibile all'utente oppure puoi consentire all'utente di visualizzare il download nell'area di notifica. È inoltre possibile registrare un BroadcastReceiverper ricevere una notifica al termine del download. La configurazione è molto semplice, fare riferimento al progetto collegato per il codice di esempio.

L'utilizzo di DownloadManagernon è generalmente una buona idea se si desidera visualizzare anche l'immagine, poiché è necessario leggere e decodificare il file salvato invece di impostare semplicemente il file scaricato Bitmapin un file ImageView. Il DownloadManagerinoltre, non fornisce alcuna API per voi app per monitorare l'avanzamento del download.

-

Ora l'introduzione della grande roba: le biblioteche. Possono fare molto di più che scaricare e visualizzare immagini, tra cui: creare e gestire la memoria / cache del disco, ridimensionare le immagini, trasformarle e altro ancora.

Inizierò con Volley , una potente libreria creata da Google e coperta dalla documentazione ufficiale. Pur essendo una libreria di rete generica non specializzata in immagini, Volley offre un'API piuttosto potente per la gestione delle immagini.

Dovrai implementare una classe Singleton per gestire le richieste di Volley e sei a posto.

Potresti voler sostituire il tuo ImageViewcon Volley's NetworkImageView, quindi il download diventa fondamentalmente un one-liner:

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

Se hai bisogno di più controllo, ecco come si crea 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 ricordare che Volley offre un eccellente meccanismo di gestione degli errori fornendo la VolleyErrorclasse che ti aiuta a determinare la causa esatta di un errore. Se la tua app fa molto networking e la gestione delle immagini non è il suo scopo principale, Volley è perfetta per te.

-

Picasso di Square è una famosa libreria che farà tutto il caricamento delle immagini per te. La semplice visualizzazione di un'immagine utilizzando Picasso è semplice come:

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

Per impostazione predefinita, Picasso gestisce la cache del disco / memoria, quindi non devi preoccuparti di questo. Per un maggiore controllo puoi implementare l' Targetinterfaccia e usarla per caricare la tua immagine - questo fornirà callback simili all'esempio Volley. Controlla il progetto demo per esempi.

Picasso ti consente anche di applicare trasformazioni all'immagine scaricata e ci sono anche altre librerie in giro che estendono quelle API. Funziona anche molto bene in un RecyclerView/ ListView/ GridView.

-

Universal Image Loader è un'altra libreria molto popolare che serve per la gestione delle immagini. Usa il proprio ImageLoaderche (una volta inizializzato) ha un'istanza globale che può essere utilizzata per scaricare immagini in una singola riga di codice:

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

Se desideri monitorare l'avanzamento del download o accedere al download 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
                }
            });

L' optsargomento in questo esempio è un DisplayImageOptionsoggetto. Fare riferimento al progetto demo per saperne di più.

Simile a Volley, UIL fornisce la FailReasonclasse che ti consente di verificare cosa è andato storto in caso di download non riuscito. Per impostazione predefinita, UIL mantiene una memoria / cache del disco se non gli dici esplicitamente di non farlo.

Nota : l'autore ha detto che non manterrà più il progetto dal 27 novembre 2015. Ma poiché ci sono molti collaboratori, possiamo sperare che Universal Image Loader continui a vivere.

-

Fresco di Facebook è la più recente e (IMO) la libreria più avanzata che porta la gestione delle immagini a un nuovo livello: dal tenere Bitmapslontano l'heap java (prima di Lollipop) al supporto di formati animati e streaming JPEG progressivo .

Per saperne di più sulle idee e le tecniche alla base di Fresco, fare riferimento a questo post .

L'utilizzo di base è abbastanza semplice. Nota che dovrai chiamare Fresco.initialize(Context);solo una volta, preferibile in Applicationclasse. L'inizializzazione di Fresco più di una volta può portare a comportamenti imprevedibili ed errori OOM.

Fresco usa Drawees per visualizzare le immagini, puoi immaginarle come di 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" />

Come puoi vedere, molte cose (comprese le opzioni di trasformazione) vengono già definite in XML, quindi tutto ciò che devi fare per visualizzare un'immagine è una riga:

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

Fresco fornisce un'API di personalizzazione estesa, che, in circostanze, può essere piuttosto complessa e richiede all'utente di leggere attentamente i documenti (sì, a volte è necessario RTFM).

Ho incluso esempi per JPEG progressivi e immagini animate nel progetto di esempio.


Conclusione - "Ho imparato a conoscere le cose fantastiche, cosa dovrei usare ora?"

Si noti che il testo seguente riflette la mia opinione personale e non dovrebbe essere preso come un postulato.

  • Se hai solo bisogno di scaricare / salvare / visualizzare alcune immagini, non prevedi di usarle in un Recycler-/Grid-/ListViewe non hai bisogno di un intero gruppo di immagini per essere pronto per la visualizzazione, BasicImageDownloader dovrebbe soddisfare le tue esigenze.
  • Se la tua app salva le immagini (o altri file) come risultato di un utente o di un'azione automatizzata e non hai bisogno che le immagini vengano visualizzate spesso, utilizza Android DownloadManager .
  • Se la tua app fa molto networking, trasmette / riceve JSONdati, funziona con le immagini, ma questo non è lo scopo principale dell'app, vai con Volley .
  • La tua app è incentrata sull'immagine / sui media, vorresti applicare alcune trasformazioni alle immagini e non vuoi preoccuparti di API complesse: usa Picasso (Nota: non fornisce alcuna API per tracciare lo stato del download intermedio) o Universal Image Caricatore
  • Se la tua app è incentrata sulle immagini, hai bisogno di funzionalità avanzate come la visualizzazione di formati animati e sei pronto per leggere i documenti, vai con Fresco .

Nel caso ve lo foste perso, il link Github per il progetto demo.


Ed ecco il file 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;
        }
      }
   }

Che dire del callback onPictureTaken () che fornisce l'immagine come byte [], si può ottenere un URL a quell'immagine, direttamente dalla fotocamera? O il vecchio outputStream () di base è l'unico modo in Android per salvare un'immagine che è stata scattata da una fotocamera senza utilizzare l'intento integrato? Sembra strano, perché la cosa naturale da fare dopo onPictureTaken è ovviamente salvarlo. Non c'è un supporto particolare per farlo?
Tombola

2
@Tombola Ciao! Questo post riguarda il download di un'immagine dal web. Ma per rispondere alla tua domanda (per quanto ho capito): il modo comune di salvare un'immagine della fotocamera è ottenere il suo percorso da Cursor(nel onActivityResult()metodo), quindi creare un Bitmappercorso utilizzando quel percorso. E sì, non eviterai di usare a FileOutputStreame a ByteArrayOutputStreamse vuoi salvare questa immagine su SD.
Droidman

@BartBurg questa domanda riguarda il download e il salvataggio di un'immagine. Ma hai ragione a un certo punto, dato che esiste un metodo di scrittura, dovrebbe esserci anche un metodo di lettura per ragioni di completezza. Lo aggiungerò presto nel prossimo aggiornamento a questo post.
Droidman

Puoi fornire un esempio usando questo BasicImageDownloader?
Jaydev

1
@JaydevKalivarapu per favore controlla l'app demo su GitHub ( classe sorgente contenente esempio )
Droidman

35

Sono appena tornato dalla risoluzione di questo problema e vorrei condividere il codice completo che può scaricare, salvare sulla sdcard (e nascondere il nome del file) e recuperare le immagini e infine controlla se l'immagine è già lì. L'URL proviene dal database, quindi il nome del file può essere facilmente utilizzato utilizzando id.

prime immagini di download

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

Quindi creare una classe per salvare e recuperare i file

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

Quindi Per accedere alle immagini prima controlla se è già lì, altrimenti scarica

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

Nota : sebbene questo esempio possa generalmente funzionare, non fornisce alcuna gestione degli errori e manca anche di una conoscenza di base dei AsyncTaskvantaggi di (uso corretto della parametrizzazione, esecuzione parallela ..). Fare riferimento ai miei esempi di seguito per i dettagli. PS . per coloro che potrebbero pensare che ho scritto questo per promuovere il mio codice per qualsiasi motivo: no, sto solo indicando i problemi che posso vedere nell'esempio fornito.
Droidman

Sì Droidman, sono d'accordo con te. Questo pezzo di codice dovrebbe essere preso come un tampone e uno deve completarlo da solo, inclusa la gestione degli errori. A proposito, anche il tuo codice manca di gestione degli errori. Che ne sarà della tua connessione e dei tuoi stream in caso di IOException?
Andama

@Andama, per favore, dai un'occhiata più da vicino al mio downloadmetodo, in particolare al doInBackgroundmetodo dell'attività che utilizzo. Un IOExceptionsarebbe atterrato nel catch (Throwable e)blocco, risultando in un ImageErroressere restituito e la onError()richiamata sarebbe stata attivata. L' ImageErroroggetto conterrà la traccia dello stack originale e la causa dell'accadutoException
Droidman

1
Sì, ma la tua connessione non verrà disconnessa e i tuoi stream non verranno chiusi
Andama

@Andama ah, capisco il tuo punto. Anche se non ho mai notato perdite sospette sui miei dispositivi di prova, questo comportamento potrebbe essere diverso su altri dispositivi. Grazie per il suggerimento - Ho aggiornato il codice
Droidman

32

Perché hai davvero bisogno del tuo codice per scaricarlo? Che ne dici di passare il tuo URI al Download manager?

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

}

1
Esempio perfetto per api> 8.
Jeeten Parmar

Il tuo codice funziona perfettamente per un'immagine! cosa posso fare se voglio scaricare più (100 immagini) dal mio file di immagini nel mio server ???
Kostantinos Ibra

Ricevo un messaggio che dice che il file è danneggiato!
Anup

2
Forse, .setDestinationInExternalPublicDir ("/ AnhsirkDasarp", "fileName.jpg");
esperto vuole essere il

2
Come facciamo a sapere se è stato scaricato correttamente o non è riuscito
Prabs

12

potrebbe aiutarti ..

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

6

Ho una soluzione semplice che funziona perfettamente. Il codice non è mio, l'ho trovato su questo link . Ecco i passaggi da seguire:

1. Prima di scaricare l'immagine, scriviamo un metodo per salvare bitmap in un file immagine nella memoria interna di Android. Ha bisogno di un contesto, meglio usare il passaggio nel contesto dell'applicazione di getApplicationContext (). Questo metodo può essere scaricato nella tua classe Activity o in altre classi util.

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. Ora abbiamo un metodo per salvare la bitmap in un file immagine in andorid, scriviamo AsyncTask per il download di immagini tramite url. Questa classe privata deve essere inserita nella classe Attività come sottoclasse. Dopo aver scaricato l'immagine, nel metodo onPostExecute, chiama il metodo saveImage definito sopra per salvare l'immagine. Nota, il nome dell'immagine è hardcoded come "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. L'AsyncTask per il download dell'immagine è definito, ma dobbiamo eseguirlo per eseguire quell'AsyncTask. Per fare ciò, scrivi questa riga nel tuo metodo onCreate nella tua classe Activity, o in un metodo onClick di un pulsante o in altri posti che ritieni adatti.

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

L'immagine dovrebbe essere salvata in /data/data/your.app.packagename/files/my_image.jpeg, controlla questo post per accedere a questa directory dal tuo dispositivo.

IMO questo risolve il problema! Se desideri ulteriori passaggi come caricare l'immagine, puoi seguire questi passaggi aggiuntivi:

4. Dopo che l'immagine è stata scaricata, abbiamo bisogno di un modo per caricare l'immagine bitmap dalla memoria interna, in modo da poterla utilizzare. Scriviamo il metodo per caricare la bitmap dell'immagine. Questo metodo richiede due parametri, un contesto e un nome file immagine, senza il percorso completo, context.openFileInput (imageName) cercherà il file nella directory di salvataggio quando questo nome file è stato salvato nel metodo saveImage sopra.

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. Ora abbiamo tutto ciò di cui abbiamo bisogno per impostare l'immagine di un ImageView o di qualsiasi altra vista su cui desideri utilizzare l'immagine. Quando salviamo l'immagine, abbiamo codificato il nome dell'immagine come "my_image.jpeg", ora possiamo passare questo nome dell'immagine al metodo loadImageBitmap sopra per ottenere la bitmap e impostarla su ImageView.

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

6. Per ottenere il percorso completo dell'immagine in base al nome dell'immagine.

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

7. Verificare se il file immagine esiste.

File file =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. Per eliminare il file immagine.

    File file = getApplicationContext (). GetFileStreamPath ("my_image.jpeg"); if (file.delete ()) Log.d ("file", "my_image.jpeg cancellato!");


0

questo codice funziona perfettamente nel mio progetto

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

1
ciao, grazie per il contributo. Nota che l'approccio di cui sopra per salvare l'immagine nella memoria privata dell'app ha 2 svantaggi: 1) l'immagine sarà disponibile solo per la tua app e 2) dovresti evitare di salvare le immagini nella memoria privata dell'app poiché non è destinata a contenuti di grandi dimensioni.
Droidman

0

Prova questo

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

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

PRODUZIONEinserisci qui la descrizione dell'immagine

Assicurati di aver aggiunto l'autorizzazione per scrivere dati in memoria

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.