如何从 Android 中的给定 url 下载和保存图像?
11 回答
从 30.12.2015 开始编辑 - 图像下载的终极指南
最后一次重大更新:2016 年 3 月 31 日
TL;DR aka 别说话,给我代码!
跳到这篇文章的底部,将
BasicImageDownloader
(javadoc version here)复制到你的项目中,实现OnImageLoaderListener
接口,你就完成了。注意:虽然
BasicImageDownloader
处理可能的错误并防止您的应用程序在出现任何问题时崩溃,但它不会对下载的Bitmaps
.
由于这篇文章受到了很多关注,我决定彻底修改它,以防止人们使用过时的技术、糟糕的编程实践或只是做一些愚蠢的事情——比如寻找“黑客”来在主线程上运行网络或接受所有 SSL 证书。
我创建了一个名为“Image Downloader”的演示项目,它演示了如何使用我自己的下载器实现、Android 的内置DownloadManager
以及一些流行的开源库来下载(和保存)图像。您可以在 GitHub 上查看完整的源代码或下载项目。
注意:我还没有调整 SDK 23+ (Marshmallow) 的权限管理,因此该项目针对的是 SDK 22 (Lollipop)。
在这篇文章结尾的结论中,我将分享我对我提到的每种特定图像下载方式的正确用例的拙见。
让我们从一个自己的实现开始(您可以在文章末尾找到代码)。首先,这是一个基本的 ImageDownloader,仅此而已。它所做的只是连接到给定的 url,读取数据并尝试将其解码为Bitmap
,并在适当的时候触发OnImageLoaderListener
接口回调。这种方法的优点 - 它很简单,您可以清楚地了解正在发生的事情。如果您只需要下载/显示和保存一些图像,而您不关心维护内存/磁盘缓存,这是一个好方法。
注意:如果图像很大,您可能需要缩小它们。
--
Android DownloadManager是一种让系统为您处理下载的方法。它实际上能够下载任何类型的文件,而不仅仅是图像。您可以让您的下载静默进行并且对用户不可见,或者您可以让用户在通知区域中看到下载。您也可以注册一个BroadcastReceiver
以在下载完成后收到通知。设置非常简单,请参阅链接项目以获取示例代码。
DownloadManager
如果您还想显示图像,则使用通常不是一个好主意,因为您需要读取和解码保存的文件,而不仅仅是将下载的文件设置Bitmap
为ImageView
. DownloadManager
也没有为您的应用程序提供任何 API 来跟踪下载进度。
--
现在介绍伟大的东西 - 图书馆。他们可以做的不仅仅是下载和显示图像,包括:创建和管理内存/磁盘缓存、调整图像大小、转换图像等等。
我将从Volley开始,这是一个由 Google 创建并包含在官方文档中的强大库。虽然是一个不专门处理图像的通用网络库,但 Volley 具有非常强大的 API 来管理图像。
您将需要实现一个Singleton类来管理 Volley 请求,并且一切顺利。
你可能想ImageView
用 Volley's替换你的NetworkImageView
,所以下载基本上变成了单行:
((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());
ImageRequest
如果您需要更多控制,这就是用 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
}
});
值得一提的是,Volley 提供了一个出色的错误处理机制,它提供了一个VolleyError
类来帮助您确定错误的确切原因。如果您的应用程序进行大量网络连接并且管理图像不是其主要目的,那么 Volley 非常适合您。
--
Square 的Picasso是一个著名的库,它将为您完成所有图像加载工作。仅使用 Picasso 显示图像就很简单:
Picasso.with(myContext)
.load(url)
.into(myImageView);
默认情况下,毕加索管理磁盘/内存缓存,因此您无需担心。要获得更多控制,您可以实现该Target
接口并使用它来加载您的图像 - 这将提供类似于 Volley 示例的回调。检查演示项目以获取示例。
Picasso 还允许您对下载的图像应用转换,甚至还有其他库可以扩展这些 API。RecyclerView
在/ ListView
/中也能很好地工作GridView
。
--
Universal Image Loader是另一个非常流行的用于图像管理的库。它使用自己的ImageLoader
that(一旦初始化)有一个全局实例,可用于在一行代码中下载图像:
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 会维护一个内存/磁盘缓存。
注意:作者提到他在 2015 年 11 月 27 日不再维护该项目。但是由于贡献者很多,我们可以希望 Universal Image Loader 继续存在。
--
Facebook 的Fresco是最新和 (IMO) 最先进的库,它将图像管理提升到一个新的水平:从Bitmaps
远离 Java 堆(在 Lollipop 之前)到支持动画格式和渐进式 JPEG 流。
要了解有关 Fresco 背后的想法和技术的更多信息,请参阅这篇文章。
基本用法非常简单。请注意,您 Fresco.initialize(Context);
只需要调用一次,最好在Application
课堂上调用。多次初始化 Fresco 可能会导致不可预知的行为和 OOM 错误。
Fresco 使用Drawee
s 来显示图像,你可以把它们想象成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" />
如您所见,很多东西(包括转换选项)已经在 XML 中定义了,所以显示图像所需要做的就是单行:
mDrawee.setImageURI(Uri.parse(url));
Fresco 提供了一个扩展的自定义 API,在某些情况下,它可能非常复杂,需要用户仔细阅读文档(是的,有时您需要RTFM)。
我在示例项目中包含了渐进式 JPEG 和动画图像的示例。
结论 - “我已经了解了很棒的东西,我现在应该使用什么?”
请注意,以下文字反映了我的个人观点,不应被视为假设。
- 如果您只需要下载/保存/显示一些图像,不打算在 a 中使用它们
Recycler-/Grid-/ListView
并且不需要一大堆图像即可显示,BasicImageDownloader应该满足您的需求。 - 如果您的应用由于用户或自动操作而保存图像(或其他文件),并且您不需要经常显示图像,请使用 Android下载管理器。
- 如果您的应用程序进行大量联网、传输/接收
JSON
数据、处理图像,但这些不是应用程序的主要目的,请使用Volley。 - 您的应用以图像/媒体为中心,您想对图像应用一些转换并且不想打扰复杂的 API:使用Picasso(注意:不提供任何 API 来跟踪中间下载状态)或Universal Image装载机
- 如果您的应用程序都是关于图像的,您需要显示动画格式等高级功能,并且您已准备好阅读文档,请使用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_);
}
}
}
然后,创建一个用于保存和检索文件的类。
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 传递给下载管理器怎么样?
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);
}
此代码可能会对您有所帮助。
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();
}
}
});
我有一个运行良好的简单解决方案。代码不是我的,我在这个链接上找到的。以下是要遵循的步骤:
1.在下载图片之前,我们先写一个方法,将位图保存到android内部存储的图片文件中。它需要一个上下文,最好通过 getApplicationContext() 在应用程序上下文中使用传递。此方法可以转储到您的 Activity 类或其他实用程序类中。
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中将位图保存到图片文件中的方法,我们来写一个通过url下载图片的AsyncTask。这个私有类需要作为子类放在你的 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 方法中,或在按钮的 onClick 方法中或您认为合适的其他地方编写此行。
new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");
图像应保存在 /data/data/your.app.packagename/files/my_image.jpeg 中,查看这篇文章以从您的设备访问此目录。
IMO这解决了这个问题!如果您想要进一步的步骤,例如加载图像,您可以按照以下额外步骤操作:
4.图像下载完成后,我们需要一种方法从内部存储中加载图像位图,这样我们就可以使用它了。让我们编写加载图像位图的方法。该方法有两个参数,一个上下文和一个图像文件名,如果没有完整路径,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 或您喜欢在其上使用图像的任何其他 View 的图像所需的一切。当我们保存图像时,我们将图像名称硬编码为“my_image.jpeg”,现在我们可以将此图像名称传递给上面的 loadImageBitmap 方法来获取位图并将其设置为 ImageView。
someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));
6.通过图片名称获取图片完整路径。
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!");
删除图像文件。
文件文件 = getApplicationContext().getFileStreamPath("my_image.jpeg"); if (file.delete()) Log.d("file", "my_image.jpeg 已删除!");
在 android studio 中下载图片的代码:
DownloadManager downloadManager =
(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setNotificationVisibility
(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadManager.enqueue(request);
FancyToast.makeText(getApplicationContext(), "Downloaded",
FancyToast.LENGTH_SHORT, FancyToast.SUCCESS, false).show();
这段代码在我的项目中完美运行
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();
}
}
试试这个
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 = "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();
}
}
}
}
确保您添加了在内存中写入数据的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@Droidman 的帖子非常全面。Volley 适用于几 KB 的小数据。当我尝试使用“BasicImageDownloader.java”时,Android Studio 警告我 AsyncTask 类应该是静态的,否则可能存在泄漏。我在另一个测试应用程序中使用了 Volley,并且由于泄漏而一直崩溃,所以我担心使用 Volley 作为图像下载器(图像可能只有 100 kB)。
我使用了毕加索,效果很好,上面发布的内容有很小的变化(可能是毕加索的更新)。下面的代码对我有用:
public static void imageDownload(Context ctx, String url){
Picasso.get().load(yourURL)
.into(getTarget(url));
}
private static Target getTarget(final String url){
Target target2 = new Target() {
@Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
@Override
public void run() {
File file = new File(localPath + "/"+"YourImageFile.jpg");
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.flush();
ostream.close();
} catch (IOException e) {
Log.e("IOException", e.getLocalizedMessage());
}
}
}).start();
}
@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
return target;
}
正如谷歌所说,现在,不要忘记在清单中添加也可读的外部存储:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
来源:http: //developer.android.com/training/basics/data-storage/files.html#GetWritePermission