Dro*_*man 221
last major update: Mar 31 2016
TL;DR a.k.a. stop talking, just give me the code!!
Skip to the bottom of this post, copy the
BasicImageDownloader
(javadoc version here) into your project, implement theOnImageLoaderListener
interface and you're done.Note: though the
BasicImageDownloader
handles possible errors and will prevent your app from crashing in case anything goes wrong, it will not perform any post-processing (e.g. downsizing) on the downloadedBitmaps
.
Since this post has received quite a lot of attention, I have decided to completely rework it to prevent the folks from using deprecated technologies, bad programming practices or just doing silly things - like looking for "hacks" to run network on the main thread or accept all SSL certs.
I've created a demo project named "Image Downloader" that demonstrates how to download (and save) an image using my own downloader implementation, the Android's built-in DownloadManager
as well as some popular open-source libraries. You can view the complete source code or download the project on GitHub.
Note: I have not adjusted the permission management for SDK 23+ (Marshmallow) yet, thus the project is targeting SDK 22 (Lollipop).
在本文末尾的结论中,我将分享我对于我提到的每种特定图像下载方式的正确用例的拙见.
让我们从一个自己的实现开始(你可以在帖子的末尾找到代码).首先,这是一个Basic ImageDownloader,就是这样.它只是连接到给定的URL,读取数据并尝试将其解码为a Bitmap
,OnImageLoaderListener
在适当时触发接口回调.这种方法的优点 - 它很简单,你可以清楚地了解正在发生的事情.如果您只需要下载/显示并保存一些图像,那么这是一个很好的方法,同时您不关心维护内存/磁盘缓存.
注意:如果图像较大,您可能需要缩小图像.
-
Android DownloadManager是一种让系统为您处理下载的方法.它实际上能够下载任何类型的文件,而不仅仅是图像.您可以让您的下载以静默方式发生,并且对用户不可见,或者您可以让用户在通知区域中查看下载.您也可以注册一个BroadcastReceiver
以在下载完成后收到通知.设置非常简单,请参阅链接项目以获取示例代码.
DownloadManager
如果您还想显示图像,使用通常不是一个好主意,因为您需要读取和解码保存的文件,而不是仅将下载设置Bitmap
为ImageView
.它DownloadManager
也没有为您的应用提供任何API来跟踪下载进度.
-
现在介绍伟大的东西 - 图书馆.他们可以做的不仅仅是下载和显示图像,包括:创建和管理内存/磁盘缓存,调整图像大小,转换图像等等.
我将从Volley开始,这是一个由Google创建并由官方文档覆盖的强大库.作为一个不专注于图像的通用网络库,Volley具有非常强大的API来管理图像.
You will need to implement a Singleton class for managing Volley requests and you are good to go.
You might want to replace your ImageView
with Volley's NetworkImageView
, so the download basically becomes a one-liner:
((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());
Run Code Online (Sandbox Code Playgroud)
If you need more control, this is what it looks like to create an ImageRequest
with 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
}
});
Run Code Online (Sandbox Code Playgroud)
It is worth mentioning that Volley features an excellent error handling mechanism by providing the VolleyError
class that helps you to determine the exact cause of an error. If your app does a lot of networking and managing images isn't its main purpose, then Volley it a perfect fit for you.
--
Square's Picasso是一个着名的图书馆,可以为您完成所有图像加载.只使用Picasso显示图像非常简单:
Picasso.with(myContext)
.load(url)
.into(myImageView);
Run Code Online (Sandbox Code Playgroud)
默认情况下,Picasso管理磁盘/内存缓存,因此您无需担心这一点.为了获得更多控制,您可以实现Target
界面并使用它来加载图像 - 这将提供类似于Volley示例的回调.查看演示项目中的示例.
Picasso还允许您对下载的图像应用转换,甚至还有其他库可以扩展这些API.在RecyclerView
/ ListView
/中也很好用GridView
.
-
Universal Image Loader is an another very popular library serving the purpose of image management. It uses its own ImageLoader
that (once initialized) has a global instance which can be used to download images in a single line of code:
ImageLoader.getInstance().displayImage(url, myImageView);
Run Code Online (Sandbox Code Playgroud)
If you want to track the download progress or access the downloaded 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
}
});
Run Code Online (Sandbox Code Playgroud)
The opts
argument in this example is a DisplayImageOptions
object. Refer to the demo project to learn more.
Similar to Volley, UIL provides the FailReason
class that enables you to check what went wrong on download failure. By default, UIL maintains a memory/disk cache if you don't explicitly tell it not to do so.
Note: the author has mentioned that he is no longer maintaining the project as of Nov 27th, 2015. But since there are many contributors, we can hope that the Universal Image Loader will live on.
--
Facebook's Fresco is the newest and (IMO) the most advanced library that takes image management to a new level: from keeping Bitmaps
off the java heap (prior to Lollipop) to supporting animated formats and progressive JPEG streaming.
To learn more about ideas and techniques behind Fresco, refer to this post.
The basic usage is quite simple. Note that you'll need to call Fresco.initialize(Context);
only once, preferable in the Application
class. Initializing Fresco more than once may lead to unpredictable behavior and OOM errors.
Fresco uses Drawee
s to display images, you can think of them as of 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" />
Run Code Online (Sandbox Code Playgroud)
As you can see, a lot of stuff (including transformation options) gets already defined in XML, so all you need to do to display an image is a one-liner:
mDrawee.setImageURI(Uri.parse(url));
Run Code Online (Sandbox Code Playgroud)
Fresco provides an extended customization API, which, under circumstances, can be quite complex and requires the user to read the docs carefully (yes, sometimes you need to RTFM).
I have included examples for progressive JPEG's and animated images into the sample project.
Note that the following text reflects my personal opinion and should not be taken as a postulate.
Recycler-/Grid-/ListView
and don't need a whole bunch of images to be display-ready, the BasicImageDownloader should fit your needs.JSON
data, works with images, but those are not the main purpose of the app, go with Volley.In case you missed that, the Github link for the demo project.
And here's the 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Nas*_*Sr. 33
我刚刚解决了这个问题,我想分享可以下载的完整代码,保存到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_);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个用于保存和检索文件的类
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 ;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,要访问图像,首先检查它是否已经存在,如果没有,然后下载
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() ;
}
Run Code Online (Sandbox Code Playgroud)
Anh*_*arp 31
为什么你真的需要自己的代码来下载它?如何将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);
}
Run Code Online (Sandbox Code Playgroud)
Aja*_*jay 12
它可能会帮助你..
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();
}
}
});
Run Code Online (Sandbox Code Playgroud)
小智 5
我有一个简单的解决方案,可以正常工作。该代码不是我的,我在此链接上找到了。以下是要遵循的步骤:
1.在下载图像之前,让我们编写一种将位图保存到android内部存储器中的图像文件中的方法。它需要一个上下文,最好是通过getApplicationContext()在应用程序上下文中使用传递。该方法可以转储到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();
}
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
3.定义了用于下载映像的AsyncTask,但是我们需要执行它才能运行该AsyncTask。为此,请在Activity类的onCreate方法中或您认为合适的按钮或其他位置的onClick方法中编写此行。
new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");
Run Code Online (Sandbox Code Playgroud)
该图像应保存在/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;
}
Run Code Online (Sandbox Code Playgroud)
5.现在,我们拥有设置ImageView或您希望在其上使用该图像的任何其他View的图像所需的一切。保存图像时,我们将图像名称硬编码为“ my_image.jpeg”,现在可以将此图像名称传递给上述loadImageBitmap方法以获取位图并将其设置为ImageView。
someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));
Run Code Online (Sandbox Code Playgroud)
6.通过图像名称获取图像的完整路径。
File file = getApplicationContext().getFileStreamPath("my_image.jpeg");
String imageFullPath = file.getAbsolutePath();
Run Code Online (Sandbox Code Playgroud)
7.检查图像文件是否存在。
文件文件=
getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
Run Code Online (Sandbox Code Playgroud)
删除图像文件。
文件file = getApplicationContext()。getFileStreamPath(“ my_image.jpeg”); 如果(file.delete())Log.d(“文件”,“ my_image.jpeg已删除!”);
归档时间: |
|
查看次数: |
198249 次 |
最近记录: |