96 votes

Comment télécharger et enregistrer une image dans Android

Comment télécharger et enregistrer une image à partir d'une url donnée dans Android ?

230voto

Droidman Points 2577

Modifié au 30.12.2015 - Le guide ultime du téléchargement d'images


dernière mise à jour majeure : 31 mars 2016


TL;DR a.k.a. arrêtez de parler, donnez moi juste le code ! !!

Passez au bas de ce post, copiez le BasicImageDownloader (version javadoc aquí ) dans votre projet, implémentez le OnImageLoaderListener interface et le tour est joué.

Note : bien que le BasicImageDownloader gère les erreurs éventuelles et empêchera votre application de se planter en cas de problème. post-traitement (par exemple, réduction de la taille) sur les fichiers téléchargés. Bitmaps .


Comme cet article a reçu beaucoup d'attention, j'ai décidé de le retravailler complètement pour empêcher les gens d'utiliser des technologies obsolètes, de mauvaises pratiques de programmation ou simplement de faire des choses stupides - comme chercher des "hacks" pour exécuter le réseau sur le thread principal ou accepter tous les certificats SSL.

J'ai créé un projet de démonstration nommé "Image Downloader" qui montre comment télécharger (et sauvegarder) une image en utilisant ma propre implémentation du téléchargeur, le module intégré d'Android et le logiciel de gestion des images. DownloadManager ainsi que certaines bibliothèques open-source populaires. Vous pouvez consulter le code source complet ou télécharger le projet. sur GitHub .

Note : Je n'ai pas encore ajusté la gestion des autorisations pour le SDK 23+ (Marshmallow), le projet vise donc le SDK 22 (Lollipop).

Dans mon conclusion à la fin de ce post, je vais partager mon humble avis sur le cas d'utilisation approprié pour chaque méthode particulière de téléchargement d'images que j'ai mentionnée.

Commençons par une implémentation personnelle (vous trouverez le code à la fin de l'article). Tout d'abord, il s'agit d'un Base ImageDownloader et c'est tout. Tout ce qu'il fait est de se connecter à l'url donnée, de lire les données et d'essayer de les décoder en tant que Bitmap ce qui déclenche le OnImageLoaderListener les rappels de l'interface, le cas échéant. L'avantage de cette approche : elle est simple et vous avez une vue d'ensemble claire de ce qui se passe. C'est une bonne solution si tout ce dont vous avez besoin est de télécharger/afficher et sauvegarder quelques images, sans vous soucier de maintenir un cache mémoire/disque.

Remarque : en cas d'images de grande taille, vous devrez peut-être les mettre à l'échelle vers le bas .

--

Android DownloadManager est un moyen de laisser le système gérer le téléchargement à votre place. Il est en fait capable de télécharger tout type de fichiers, pas seulement des images. Vous pouvez laisser votre téléchargement se dérouler de manière silencieuse et invisible pour l'utilisateur, ou vous pouvez permettre à l'utilisateur de voir le téléchargement dans la zone de notification. Vous pouvez également enregistrer un BroadcastReceiver pour être informé de la fin du téléchargement. L'installation est assez simple, référez-vous au projet lié pour un exemple de code.

Utilisation de la DownloadManager n'est généralement pas une bonne idée si vous souhaitez également afficher l'image, car vous devrez lire et décoder le fichier enregistré au lieu de simplement définir le fichier téléchargé. Bitmap dans un ImageView . Le site DownloadManager ne fournit pas non plus d'API permettant à votre application de suivre la progression du téléchargement.

--

Maintenant, l'introduction de la grande chose - les bibliothèques. Elles peuvent faire beaucoup plus que simplement télécharger et afficher des images, notamment : créer et gérer le cache mémoire/disque, redimensionner les images, les transformer et plus encore.

Je vais commencer par Volley-ball une bibliothèque puissante créée par Google et couverte par la documentation officielle. Bien qu'il s'agisse d'une bibliothèque réseau polyvalente non spécialisée dans les images, Volley dispose d'une API assez puissante pour la gestion des images.

Vous devrez mettre en œuvre un Singleton pour la gestion des demandes Volley et vous êtes prêt à partir.

Vous pourriez vouloir remplacer votre ImageView avec Volley's NetworkImageView Le téléchargement se résume donc à une seule phrase :

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

Si vous avez besoin de plus de contrôle, voici à quoi ressemble la création d'une ImageRequest avec 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
                }
            });

Il convient de mentionner que Volley dispose d'un excellent mécanisme de gestion des erreurs grâce à la fonction VolleyError qui vous aide à déterminer la cause exacte d'une erreur. Si votre application fait beaucoup de mise en réseau et que la gestion des images n'est pas son objectif principal, alors Volley est la solution idéale pour vous.

--

Carré Picasso est une bibliothèque bien connue qui se charge de charger toutes les images pour vous. L'affichage d'une image à l'aide de Picasso est très simple :

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

Par défaut, Picasso gère le cache disque/mémoire, vous n'avez donc pas à vous en soucier. Pour plus de contrôle, vous pouvez implémenter la fonction Target et utilisez-la pour charger votre image - cela fournira des rappels similaires à l'exemple de Volley. Consultez le projet de démonstration pour des exemples.

Picasso vous permet également d'appliquer des transformations à l'image téléchargée et il y a même autres bibliothèques autour qui étendent ces API. Fonctionne également très bien dans un RecyclerView / ListView / GridView .

--

Chargeur d'images universel est une autre bibliothèque très populaire servant à la gestion des images. Elle utilise ses propres ImageLoader qui (une fois initialisé) possède une instance globale qui peut être utilisée pour télécharger des images en une seule ligne de code :

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

Si vous souhaitez suivre la progression du téléchargement ou accéder aux données téléchargées 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
                }
            });

En opts dans cet exemple est un DisplayImageOptions objet. Reportez-vous au projet de démonstration pour en savoir plus.

Comme pour Volley, l'UIL fournit le FailReason qui vous permet de vérifier ce qui s'est mal passé lors d'un échec de téléchargement. Par défaut, l'UIL maintient un cache mémoire/disque si vous ne lui demandez pas explicitement de ne pas le faire.

Note : l'auteur a mentionné qu'il ne maintient plus le projet depuis le 27 novembre 2015. Mais comme il y a de nombreux contributeurs, nous pouvons espérer que le Universal Image Loader continuera à vivre.

--

Facebook Fresco est la bibliothèque la plus récente et (IMO) la plus avancée, qui porte la gestion des images à un niveau supérieur : de la conservation de l'image à la gestion de l'image. Bitmaps du tas de java (avant Lollipop) afin de supporter formats animés y flux JPEG progressif .

Pour en savoir plus sur les idées et les techniques qui sous-tendent Fresco, reportez-vous à ce poste .

L'utilisation de base est assez simple. Notez que vous devrez appeler Fresco.initialize(Context); une seule fois, de préférence dans le Application la classe. Initialiser Fresco plus d'une fois peut entraîner un comportement imprévisible et des erreurs OOM.

Fresco utilise Drawee pour afficher des images, vous pouvez les considérer comme des éléments de ImageView s :

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

Comme vous pouvez le constater, de nombreux éléments (y compris les options de transformation) sont déjà définis dans le XML, de sorte que tout ce que vous devez faire pour afficher une image est une simple ligne :

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

Fresco fournit une API de personnalisation étendue, qui, dans certaines circonstances, peut être assez complexe et nécessite que l'utilisateur lise attentivement la documentation (oui, parfois vous devez RTFM).

J'ai inclus des exemples de JPEG progressifs et d'images animées dans l'exemple de projet.


Conclusion - "J'ai appris ce qu'il y a de mieux, que dois-je utiliser maintenant ?"

Notez que le texte suivant reflète mon opinion personnelle et ne doit pas et ne doit pas être considéré comme un postulat.

  • Si vous n'avez besoin que de télécharger/sauvegarder/afficher certaines images, ne prévoyez pas de les utiliser dans un programme de gestion de l'image. Recycler-/Grid-/ListView et qui n'ont pas besoin de tout un tas d'images pour être prêts à être affichés, la BasicImageDownloader devrait répondre à vos besoins.
  • Si votre application enregistre des images (ou d'autres fichiers) à la suite d'une action de l'utilisateur ou d'une action automatisée et que vous n'avez pas besoin que les images soient affichées souvent, utilisez l'outil Android DownloadManager .
  • Dans le cas où votre application fait beaucoup de mise en réseau, transmet/reçoit JSON données, fonctionne avec des images, mais ce n'est pas l'objectif principal de l'application. Volley-ball .
  • Votre application est axée sur les images/médias, vous souhaitez appliquer des transformations aux images et vous ne voulez pas vous embêter avec une API complexe : utilisez Picasso (Note : ne fournit pas d'API pour suivre l'état du téléchargement intermédiaire) ou Chargeur d'images universel
  • Si votre application ne concerne que des images, que vous avez besoin de fonctions avancées comme l'affichage de formats animés et que vous êtes prêt à lire la documentation, optez pour Fresco .

Au cas où vous auriez manqué ça, le Lien Github pour le projet de démonstration.


Et voici le 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;
        }
      }
   }

35voto

Nasz Njoka Sr. Points 145

Je viens juste de résoudre ce problème et je voudrais partager le code complet qui peut télécharger, sauvegarder sur la carte SD (et cacher le nom du fichier) et récupérer les images et enfin il vérifie si l'image est déjà là. L'url provient de la base de données et le nom de fichier peut être facilement identifié à l'aide de l'identifiant.

Tout d'abord, créez une classe pour le téléchargement d'images.

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

Ensuite, créez une classe pour sauvegarder et récupérer les fichiers.

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

Ensuite, pour accéder aux images, vérifiez d'abord si elles sont déjà présentes ; sinon, téléchargez-les.

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

34voto

AnhSirk Dasarp Points 3299

Pourquoi avez-vous vraiment besoin de votre propre code pour le télécharger ? Pourquoi ne pas simplement passer votre URI au gestionnaire de téléchargement ?

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

}

13voto

Ajay Points 687

Ce code pourrait vous aider.

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

6voto

J'ai une solution simple qui fonctionne parfaitement. Le code n'est pas de moi, je l'ai trouvé sur ceci lien . Voici les étapes à suivre :

1. Avant de télécharger l'image, écrivons une méthode pour enregistrer un bitmap dans un fichier image dans le stockage interne d'Android. Elle a besoin d'un contexte, mieux vaut utiliser le passage dans le contexte de l'application par getApplicationContext(). Cette méthode peut être intégrée dans votre classe Activity ou d'autres classes utilitaires.

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. Maintenant que nous avons une méthode pour sauvegarder le bitmap dans un fichier image dans andorid, écrivons l'AsyncTask pour télécharger les images par url. Cette classe privée doit être placée dans votre classe Activity en tant que sous-classe. Après le téléchargement de l'image, dans la méthode onPostExecute, elle appelle la méthode saveImage définie ci-dessus pour enregistrer l'image. Notez que le nom de l'image est codé en dur comme "mon_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 pour le téléchargement de l'image est défini, mais nous devons l'exécuter afin d'exécuter cet AsyncTask. Pour ce faire, écrivez cette ligne dans la méthode onCreate de votre classe Activity, ou dans la méthode onClick d'un bouton ou à d'autres endroits que vous jugez appropriés.

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

L'image doit être enregistrée dans /data/data/votre.app.packagename/files/my_image.jpeg, consultez ce post pour accéder à ce répertoire depuis votre appareil.

IMO cela résout le problème ! Si vous voulez aller plus loin, par exemple charger l'image, vous pouvez suivre ces étapes supplémentaires :

4. Une fois l'image téléchargée, nous devons trouver un moyen de charger l'image bitmap depuis le stockage interne, afin de pouvoir l'utiliser. Écrivons la méthode pour charger l'image bitmap. Cette méthode prend deux paramètres, un contexte et un nom de fichier image, sans le chemin complet, le context.openFileInput(imageName) cherchera le fichier dans le répertoire de sauvegarde lorsque ce nom de fichier a été sauvegardé dans la méthode saveImage ci-dessus.

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. Nous avons maintenant tout ce dont nous avions besoin pour définir l'image d'un ImageView ou de toute autre vue sur laquelle vous souhaitez utiliser l'image. Lorsque nous avons enregistré l'image, nous avons codé en dur le nom de l'image en tant que "mon_image.jpeg", nous pouvons maintenant passer ce nom d'image à la méthode loadImageBitmap ci-dessus pour obtenir le bitmap et le définir sur une ImageView.

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

6. Pour obtenir le chemin complet de l'image par son nom.

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

7. Vérifiez si le fichier image existe.

Fichier fichier =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. Pour supprimer le fichier image.

    Fichier file = getApplicationContext().getFileStreamPath("mon_image.jpeg") ; if (file.delete()) Log.d("file", "my_image.jpeg deleted !") ;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X