Como baixar e salvar uma imagem no Android

Respostas:

224

Editar a partir de 30.12.2015 - O guia definitivo para download de imagens


última grande atualização: 31 de março de 2016


TL; DR aka pare de falar, apenas me dê o código !!

Pule para o final deste post, copie a BasicImageDownloader(versão javadoc aqui ) em seu projeto, implemente a OnImageLoaderListenerinterface e pronto.

Nota : embora BasicImageDownloaderlide com possíveis erros e evite que seu aplicativo trave caso algo dê errado, ele não executará nenhum pós-processamento (por exemplo, downsizing) no download Bitmaps.


Como este post recebeu bastante atenção, decidi retrabalhá-lo completamente para evitar que as pessoas usem tecnologias obsoletas, práticas de programação ruins ou apenas façam coisas bobas - como procurar por "hacks" para rodar a rede no thread principal ou aceitar todos os certificados SSL.

Eu criei um projeto de demonstração chamado "Image Downloader" que demonstra como baixar (e salvar) uma imagem usando minha própria implementação de downloader, o Android integrado DownloadManager, bem como algumas bibliotecas populares de código aberto. Você pode visualizar o código-fonte completo ou baixar o projeto no GitHub .

Observação : ainda não ajustei o gerenciamento de permissões para SDK 23+ (Marshmallow), portanto, o projeto está voltado para o SDK 22 (Lollipop).

Em minha conclusão no final deste post, compartilharei minha humilde opinião sobre o caso de uso adequado para cada forma particular de download de imagens que mencionei.

Vamos começar com uma implementação própria (você pode encontrar o código no final do post). Em primeiro lugar, este é um ImageDownloader básico e pronto. Tudo o que ele faz é se conectar ao url fornecido, ler os dados e tentar decodificá-los como um Bitmap, disparando os OnImageLoaderListenercallbacks da interface quando apropriado. A vantagem desta abordagem - é simples e você tem uma visão geral clara do que está acontecendo. Uma boa maneira de fazer isso se tudo que você precisa é baixar / exibir e salvar algumas imagens, embora você não se importe em manter uma memória / cache de disco.

Nota: no caso de imagens grandes, pode ser necessário reduzi-las .

-

O Android DownloadManager é uma maneira de permitir que o sistema faça o download para você. Na verdade, é capaz de baixar qualquer tipo de arquivo, não apenas imagens. Você pode permitir que o download aconteça silenciosamente e de forma invisível para o usuário ou pode permitir que o usuário veja o download na área de notificação. Você também pode registrar um BroadcastReceiverpara ser notificado após a conclusão do download. A configuração é bastante simples, consulte o projeto vinculado para obter o código de amostra.

O uso de DownloadManagergeralmente não é uma boa ideia se você também deseja exibir a imagem, já que seria necessário ler e decodificar o arquivo salvo em vez de apenas definir o baixado Bitmapem um ImageView. O DownloadManagertambém não fornece nenhuma API para que seu aplicativo acompanhe o andamento do download.

-

Agora, a introdução das grandes coisas - as bibliotecas. Eles podem fazer muito mais do que apenas baixar e exibir imagens, incluindo: criar e gerenciar a memória / cache de disco, redimensionar imagens, transformá-las e muito mais.

Vou começar com o Volley , uma biblioteca poderosa criada pelo Google e coberta pela documentação oficial. Apesar de ser uma biblioteca de rede de propósito geral não especializada em imagens, o Volley apresenta uma API bastante poderosa para gerenciar imagens.

Você precisará implementar uma classe Singleton para gerenciar as solicitações do Volley e pronto.

Você pode querer substituir o seu ImageViewpelo do Volley NetworkImageView, então o download se torna basicamente de uma linha:

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

Se você precisa de mais controle, esta é a aparência de criar um ImageRequestcom o 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
                }
            });

É importante mencionar que o Volley apresenta um excelente mecanismo de tratamento de erros, fornecendo a VolleyErrorclasse que ajuda a determinar a causa exata de um erro. Se o seu aplicativo faz muitas redes e gerencia imagens não é o seu objetivo principal, então o Volley é a escolha perfeita para você.

-

O Picasso da Square é uma biblioteca bem conhecida que fará todo o carregamento de imagens para você. Exibir uma imagem usando o Picasso é tão simples quanto:

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

Por padrão, o Picasso gerencia o cache de disco / memória, então você não precisa se preocupar com isso. Para obter mais controle, você pode implementar a Targetinterface e usá-la para carregar sua imagem - isso fornecerá retornos de chamada semelhantes ao exemplo do Volley. Verifique o projeto de demonstração para exemplos.

O Picasso também permite que você aplique transformações à imagem baixada e há até mesmo outras bibliotecas que estendem essa API. Também funciona muito bem em um RecyclerView/ ListView/ GridView.

-

Universal Image Loader é outra biblioteca muito popular que serve ao propósito de gerenciamento de imagens. Ele usa seu próprio ImageLoaderque (uma vez inicializado) tem uma instância global que pode ser usada para baixar imagens em uma única linha de código:

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

Se você deseja acompanhar o andamento do download ou acessar o baixado 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
                }
            });

O optsargumento neste exemplo é um DisplayImageOptionsobjeto. Consulte o projeto de demonstração para saber mais.

Semelhante ao Volley, o UIL fornece a FailReasonclasse que permite verificar o que deu errado em caso de falha de download. Por padrão, o UIL mantém um cache de memória / disco se você não disser explicitamente para não fazer isso.

Nota : o autor mencionou que ele não está mais mantendo o projeto em 27 de novembro de 2015. Mas como existem muitos contribuidores, podemos esperar que o Universal Image Loader continue vivo.

-

O Fresco do Facebook é a biblioteca mais nova e (IMO) mais avançada que leva o gerenciamento de imagens a um novo nível: desde evitar Bitmapso heap java (antes do Lollipop) até o suporte a formatos animados e streaming progressivo de JPEG .

Para aprender mais sobre as ideias e técnicas por trás do Fresco, consulte este post .

O uso básico é bastante simples. Observe que você precisará ligar Fresco.initialize(Context);apenas uma vez, de preferência na Applicationaula. Inicializar o Fresco mais de uma vez pode levar a um comportamento imprevisível e erros de OOM.

Fresco usa Drawees para exibir imagens, você pode pensar nelas 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 você pode ver, muitas coisas (incluindo opções de transformação) já são definidas em XML, então tudo que você precisa fazer para exibir uma imagem é uma linha:

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

Fresco fornece uma API de personalização estendida, que, sob circunstâncias, pode ser bastante complexa e requer que o usuário leia os documentos com atenção (sim, às vezes você precisa RTFM).

Incluí exemplos para JPEGs progressivos e imagens animadas no projeto de amostra.


Conclusão - "Aprendi sobre as coisas excelentes, o que devo usar agora?"

Observe que o texto a seguir reflete minha opinião pessoal e não deve ser considerado um postulado.

  • Se você só precisa baixar / salvar / exibir algumas imagens, não planeje usá-las em um Recycler-/Grid-/ListViewe não precisa de um monte de imagens para estar pronto para exibição, o BasicImageDownloader deve atender às suas necessidades.
  • Se seu aplicativo salva imagens (ou outros arquivos) como resultado de um usuário ou uma ação automatizada e você não precisa que as imagens sejam exibidas com frequência, use o Android DownloadManager .
  • Caso seu aplicativo faça muita rede, transmita / receba JSONdados, trabalhe com imagens, mas esse não seja o objetivo principal do aplicativo, vá com o Volley .
  • Seu aplicativo é focado em imagem / mídia, você gostaria de aplicar algumas transformações às imagens e não quer se preocupar com APIs complexas: use o Picasso (Observação: não fornece nenhuma API para rastrear o status intermediário de download) ou Universal Image Carregador
  • Se o seu aplicativo é tudo sobre imagens, você precisa de recursos avançados como a exibição de formatos animados e está pronto para ler os documentos, vá com Fresco .

Caso você tenha perdido isso, o link do Github para o projeto de demonstração.


E aqui está o 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;
        }
      }
   }
Droidman
fonte
E o retorno de chamada onPictureTaken () que fornece a imagem como byte [], é possível obter um URL para essa imagem, direto da câmera? Ou o outputStream () antigo básico é a única maneira no Android de salvar uma foto que foi tirada por uma câmera sem usar a intenção embutida? Isso parece estranho, porque a coisa natural a fazer depois de onPictureTaken é salvá-lo. Não há suporte específico para fazer isso?
Tômbola
2
@Tombola Hi! Esta postagem é sobre o download de uma imagem da web. Mas, para responder à sua pergunta (pelo que entendi): a maneira comum de salvar uma imagem da câmera é obter seu caminho a partir do Cursor(no onActivityResult()método) e, em seguida, criar um Bitmapusando esse caminho. E sim, você não deixará de usar um FileOutputStreame um ByteArrayOutputStreamse quiser salvar esta imagem em SD.
Droidman
@BartBurg esta questão é sobre como baixar e salvar uma imagem. Mas você está certo em algum ponto, uma vez que existe um método de gravação, também deve haver um método de leitura para fins de integridade. Eu irei adicioná-lo na próxima atualização deste post em breve.
Droidman
Você pode fornecer um exemplo usando este BasicImageDownloader?
Jaydev
1
@JaydevKalivarapu, verifique o aplicativo de demonstração no GitHub ( classe de origem contendo exemplo )
Droidman
35

Acabei de resolver este problema em e gostaria de compartilhar o código completo que posso baixar, salvar no sdcard (e ocultar o nome do arquivo) e recuperar as imagens e por fim verificar se a imagem já está lá. O url vem do banco de dados, portanto, o nome do arquivo pode ser facilmente usado com o id.

primeiro download de imagens

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

Em seguida, crie uma classe para salvar e recuperar os arquivos

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

Então, para acessar as imagens primeiro verifique se já está lá, senão faça o download

          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.
fonte
Observação : embora este exemplo possa funcionar de maneira geral, ele não fornece nenhum tratamento de erros e também carece de algum conhecimento básico das AsyncTaskvantagens do (uso adequado da parametrização, execução paralela ...). Por favor, consulte meus exemplos abaixo para obter detalhes. PS . para aqueles que podem pensar que escrevi isso para promover meu próprio código por qualquer motivo: não, estou apenas apontando os problemas que posso ver no exemplo fornecido.
Droidman
Sim Droidman, concordo com você. Este trecho de código deve ser considerado um tamplate e deve-se completá-lo por conta própria, incluindo o tratamento de erros. A propósito, seu código também carece de tratamento de erros. O que acontecerá com sua conexão e fluxos no caso de IOException?
Androider
@Androider, por favor, dê uma olhada no meu downloadmétodo, particularmente o doInBackgroundmétodo da tarefa que eu uso. Um IOExceptionpousaria no catch (Throwable e)bloco, resultando em um ImageErrorretorno e o onError()retorno de chamada acionado. O ImageErrorobjeto conterá o rastreamento de pilha original e a causa do ocorridoException
Droidman
1
Sim, mas sua conexão não será desconectada e seus streams não serão encerrados
Androider
@Androider ah, eu vejo seu ponto. Embora eu nunca tenha notado nenhum vazamento suspeito em meus dispositivos de teste, esse comportamento pode ser diferente em outros dispositivos. Obrigado pela dica - Eu atualizei o código
Droidman
32

Por que você realmente precisa de seu próprio código para baixá-lo? Que tal passar seu URI para o gerenciador de download?

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
fonte
1
Exemplo perfeito para api> 8.
Jeeten Parmar
Seu código funciona perfeitamente para uma imagem! O que posso fazer se quiser baixar mais (100 fotos) do meu arquivo de imagens no meu servidor ??
Kostantinos Ibra
Recebo uma mensagem dizendo arquivo danificado!
Anup
2
Talvez, .setDestinationInExternalPublicDir ("/ AnhsirkDasarp", "fileName.jpg");
especialista quer ser
2
Como sabemos se o download foi feito com sucesso ou falhou
Prabs de
12

pode te ajudar ..

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
fonte
6

Tenho uma solução simples que está funcionando perfeitamente. O código não é meu, encontrei neste link . Aqui estão as etapas a seguir:

1. Antes de baixar a imagem, vamos escrever um método para salvar bitmap em um arquivo de imagem no armazenamento interno do Android. Ele precisa de um contexto, melhor usar a passagem no contexto do aplicativo por getApplicationContext (). Este método pode ser despejado em sua classe Activity ou outras classes 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. Agora que temos um método para salvar bitmap em um arquivo de imagem no andorid, vamos escrever a AsyncTask para baixar imagens por url. Esta classe privada precisa ser colocada em sua classe Activity como uma subclasse. Depois de fazer o download da imagem, no método onPostExecute, ele chama o método saveImage definido acima para salvar a imagem. Observe que o nome da imagem é 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. O AsyncTask para baixar a imagem está definido, mas precisamos executá-lo para executar essa AsyncTask. Para fazer isso, escreva esta linha em seu método onCreate em sua classe Activity, ou em um método onClick de um botão ou outros lugares que você achar necessário.

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

A imagem deve ser salva em /data/data/your.app.packagename/files/my_image.jpeg, verifique esta postagem para acessar este diretório a partir do seu dispositivo.

IMO isso resolve o problema! Se desejar outras etapas, como carregar a imagem, você pode seguir estas etapas extras:

4. Após o download da imagem, precisamos encontrar uma maneira de carregar o bitmap da imagem do armazenamento interno para que possamos usá-lo. Vamos escrever o método para carregar o bitmap da imagem. Este método leva dois parâmetros, um contexto e um nome de arquivo de imagem, sem o caminho completo, o context.openFileInput (imageName) irá procurar o arquivo no diretório de salvamento quando este nome de arquivo foi salvo no método saveImage acima.

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. Agora temos tudo o que precisamos para definir a imagem de um ImageView ou de quaisquer outras visualizações em que você gostaria de usar a imagem. Quando salvamos a imagem, codificamos o nome da imagem como “my_image.jpeg”, agora podemos passar esse nome de imagem para o método loadImageBitmap acima para obter o bitmap e defini-lo como ImageView.

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

6. Para obter o caminho completo da imagem pelo nome da imagem.

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

7. Verifique se o arquivo de imagem existe.

Arquivo arquivo =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. Para excluir o arquivo de imagem.

    Arquivo file = getApplicationContext (). GetFileStreamPath ("my_image.jpeg"); if (file.delete ()) Log.d ("arquivo", "minha_imagem.jpeg excluída!");

Gláucio Leonardo Sant'ana
fonte
0

este código roda perfeitamente no meu projeto

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
fonte
1
oi, obrigado pela contribuição. Observe que a abordagem acima de salvar a imagem no armazenamento privado do aplicativo tem 2 desvantagens: 1) a imagem estará disponível apenas para o seu aplicativo e 2) você deve evitar salvar imagens no armazenamento privado do aplicativo, uma vez que não se destina a conteúdo grande.
Droidman
0

Tente isto

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

RESULTADOinsira a descrição da imagem aqui

Certifique-se de adicionar permissão para gravar dados na memória

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