如何在Android中下载和保存图像

如何从Android中的给定url下载和保存图像?

编辑截至2015年12月30日 – 图像下载的终极指南


上次重大更新:2016年3月31日


TL; DR aka停止说话,只是给我的代码!

跳到这篇文章的底部,将BasicImageDownloader ( 这里是 javadoc版本)复制到你的项目中,实现OnImageLoaderListener接口,就完成了。

注意 :虽然BasicImageDownloader处理可能的错误,并且可以防止你的应用程序在发生任何错误时崩溃,但它不会对下载的BasicImageDownloader执行任何后处理(例如缩小尺寸)。


由于这篇文章受到了很多的关注,我决定彻底改写它,以防止人们使用不赞成使用的技术,糟糕的编程习惯或者只是在做一些愚蠢的事情 – 比如寻找“黑客”来在主线程上运行networking,或者接受所有SSL证书。

我创build了一个名为“Image Downloader”的演示项目,演示如何使用我自己的下载器实现,Android内置的DownloadManager以及一些stream行的开源库来下载(和保存)图像。 您可以查看完整的源代码或在GitHub上下载项目。

注意 :我还没有调整SDK 23+(Marshmallow)的权限pipe理,因此这个项目的目标是SDK 22(Lollipop)。

在本文末尾的结论中,我将分享对我提到的每种特定图像下载方式的恰当用法的看法

让我们从自己的实现开始(你可以在post的末尾find代码)。 首先,这是一个基本的 ImageDownloader,就是这样。 它所做的只是连接到给定的URL,读取数据并尝试将其解码为Bitmap ,并在适当的时候触发OnImageLoaderListener接口callback。 这种方法的优点 – 这很简单,你可以清楚地看到发生了什么事情。 如果你需要的只是下载/显示和保存一些图像,而不关心维护内存/磁盘caching,一个好的方法。

注意:如果图像较大,可能需要缩小它们 。

Android DownloadManager是让系统为您处理下载的一种方式。 它实际上能够下载任何types的文件,而不仅仅是图像。 您可以让用户无声无息地进行下载,也可以让用户在通知区域看到下载内容。 下载完成后,您还可以注册BroadcastReceiver以获得通知。 该设置非常简单,请参阅链接的项目的示例代码。

使用DownloadManager通常不是一个好主意,因为您需要读取和解码保存的文件,而不是将下载的Bitmap设置为ImageViewDownloadManager也不会为您提供任何API来跟踪下载进度。

现在介绍伟大的东西 – 图书馆。 他们可以做的不仅仅是下载和显示图像,包括:创build和pipe理内存/磁盘caching,调整图像大小,转换图像等等。

我将从Volley开始,这是由Google创build的一个function强大的图书馆,并且包含官方文档。 Volley作为一个通用的networking库,并不是专门处理图像的,它具有相当强大的用于pipe理图像的API。

你将需要实施一个Singleton类来pipe理Volley请求,你很好。

你可能想用Volley的NetworkImageViewreplace你的ImageView ,所以下载基本上变成了一个单行的:

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

如果你需要更多的控制,这是使用Volley创build一个ImageRequest

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

值得一提的是,Volley提供了一个出色的error handling机制,通过提供VolleyError类来帮助您确定错误的确切原因。 如果你的应用程序做了很多networking连接,pipe理图像不是它的主要目的,那么Volley对你来说是一个完美的select。

广场的毕加索是一个知名的图书馆,将为您做所有的图像加载的东西。 只需使用毕加索展示图像就像下面这样简单:

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

默认情况下,毕加索pipe理磁盘/内存caching,所以你不必担心。 对于更多的控制,你可以实现Target接口,并使用它来加载你的图像 – 这将提供类似于Volley例子的callback。 检查演示项目的例子。

毕加索还允许您将转换应用于下载的图像,甚至还有其他库扩展了这些API。 在RecyclerView / ListView / GridView也很好。

通用图像加载器是另一个非常受欢迎的图像库服务的图像pipe理的目的。 它使用自己的ImageLoader (一旦初始化)有一个全局实例,可以用来下载一行代码中的图像:

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

如果要跟踪下载进度或访问下载的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 } }); 

本例中的opts参数是一个DisplayImageOptions对象。 请参阅演示项目了解更多信息。

与Volley类似,UIL提供了FailReason类,使您能够检查下载失败时出现了什么问题。 默认情况下,UIL维护一个内存/磁盘caching,如果你没有明确告诉它不这样做。

:作者提到自2015年11月27日起他不再维护该项目。但由于贡献者众多,我们希望通用映像加载器能够继续存在。

Facebook的Fresco是最新的(IMO)最先进的图像库,它将图像pipe理提升到了一个新的高度:将Bitmaps从Java堆(在Lollipop之前)保留到支持animation格式和逐行JPEGstream 。

要了解更多关于Fresco背后的想法和技术,请参阅这篇文章 。

基本用法很简单。 请注意,您需要调用Fresco.initialize(Context); 只有一次,最好在Application类。 不止一次初始化Fresco可能会导致不可预知的行为和OOM错误。

Fresco使用Drawee来显示图像,您可以将它们视为ImageView

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

正如你所看到的,很多东西(包括转换选项)已经在XML中定义了,所以你需要做的只是显示一个图像:

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

Fresco提供了一个扩展的定制API,在某些情况下,它可能相当复杂,需要用户仔细阅读文档(是的,有时需要 RTFM)。

我已经将渐进式JPEG和animation图像的示例包含在示例项目中。


结论 – “我已经了解了这些伟大的东西,现在该用什么?”

请注意,以下文字反映了我的个人意见,不应被视为假设。

  • 如果你只需要下载/保存/显示一些图像,不要计划在Recycler-/Grid-/ListView使用它们,并且不需要大量的图像来显示, BasicImageDownloader应该适合你需要。
  • 如果您的应用因用户或自动操作而保存了图片(或其他文件),并且您不需要经常显示图片,请使用Android DownloadManager
  • 如果你的应用程序做了很多networking,发送/接收JSON数据,使用图像,但这些不是应用程序的主要目的,请与Volley一起使用。
  • 您的应用程序是以图像/媒体为中心的,您希望对图像应用一些转换,而不想打扰复杂的API:使用Picasso (注意:不提供任何API来跟踪中间下载状态)或Universal Image装载机
  • 如果您的应用程序都是关于图片的,则需要显示animation格式等高级function,并且您已经准备好阅读文档,请使用Fresco

如果你错过了,演示项目的Github链接 。


这里是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; } } } 

我刚刚解决了这个问题,我想共享完整的代码,可以下载,保存到SD卡(并隐藏文件名),并检索图像,最后它检查图像是否已经在那里。 url来自数据库,所以文件名可以使用id唯一容易。

首先下载图像

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

然后创build一个保存和检索文件的类

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

然后要访问图像首先检查是否已经存在,如果没有,然后下载

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

为什么你真的需要自己的代码来下载它? 把你的URI传给下载pipe理器怎么样?

 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("/AnhsirkDasarpFiles", "fileName.jpg"); mgr.enqueue(request); } 

它可能会帮助你..

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

我有一个简单的解决scheme,完美的工作。 代码不是我的,我在这个链接上find它。 以下是要遵循的步骤:

1.在下载图像之前,我们先来编写一个在android的内部存储器中将位图保存到图像文件中的方法。 它需要一个上下文,最好通过getApplicationContext()在应用程序上下文中使用pass。 这个方法可以被转储到你的Activity类或其他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.现在我们有一个方法将位图保存到andorid中的图像文件中,我们来编写AsyncTask来通过url下载图像。 这个私有类需要作为子类放置在你的Activity类中。 在下载图像之后,在onPostExecute方法中,它调用上面定义的saveImage方法来保存图像。 请注意,图像名称被硬编码为“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.用于下载图像的AsyncTask被定义,但是我们需要执行它来运行AsyncTask。 为此,请将这行写入Activity类的onCreate方法中,或者在button或其他您认为合适的地方的onClick方法中写入。

 new DownloadImage().execute("http://developer.android.comhttp://img.dovov.comactivity_lifecycle.png"); 

该图像应该保存在/data/data/your.app.packagename/files/my_image.jpeg,检查这个post从您的设备访问此目录。

IMO解决了这个问题! 如果你想进一步的步骤,如加载图像,你可以按照这些额外的步骤:

4.下载图片后,我们需要一种方法来从内部存储器加载图像位图,所以我们可以使用它。 我们来编写加载图像位图的方法。 这个方法需要两个参数,一个上下文和一个图像文件名,没有完整的path,context.openFileInput(imageName)会在saveImage方法中保存这个文件名时在保存目录下查找文件。

 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.现在我们拥有了设置ImageView或任何其他您喜欢使用该图像的视图的图像所需的一切。 当我们保存图像时,我们将图像名称硬编码为“my_image.jpeg”,现在我们可以将这个图像名称传递给上面的loadImageBitmap方法来获取位图并将其设置为ImageView。

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

6.通过图像名称获取图像完整path。

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

7.检查图像文件是否存在。

文件文件=

 getApplicationContext().getFileStreamPath("my_image.jpeg"); if (file.exists()) Log.d("file", "my_image.jpeg exists!"); 
  1. 删除图像文件。

    File file = getApplicationContext()。getFileStreamPath(“my_image.jpeg”); if(file.delete())Log.d(“file”,“my_image.jpeg deleted!”);

这个代码完美的运行在我的项目中

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

正如谷歌所说,现在,不要忘记在清单中的外部存储上添加可读性:

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

资料来源: http : //developer.android.com/training/basics/data-storage/files.html#GetWritePermission

尝试这个

  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(); } 
 public class testCrop extends AppCompatActivity { ImageView iv; String imagePath = "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(); } } } } 

OUTPUT 在这里输入图像描述

确保你添加了在内存中写入数据的权限

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