Android에서 주어진 URL에서 이미지를 어떻게 다운로드하고 저장합니까?
답변:
마지막 주요 업데이트 : 2016 년 3 월 31 일
TL; DR 일명 그만 얘기해, 그냥 코드를 줘 !!
이 게시물의 맨 아래로 건너 뛰고
BasicImageDownloader
( 여기에서 javadoc 버전 ) 프로젝트에 복사 하고OnImageLoaderListener
인터페이스를 구현하면 완료됩니다.참고 :에서
BasicImageDownloader
가능한 오류를 처리하고 문제가 발생할 경우 앱이 다운되는 것을 방지 하지만 다운로드 한 .NET에서 사후 처리 (예 : 크기 축소)를 수행하지 않습니다Bitmaps
.
이 게시물은 많은 관심을 받았기 때문에 사람들이 더 이상 사용되지 않는 기술, 나쁜 프로그래밍 관행을 사용하거나 어리석은 일을하지 않도록 완전히 재 작업하기로 결정했습니다. 모든 SSL 인증서를 수락합니다.
필자는 자체 다운로더 구현, Android 내장 및 DownloadManager
일부 인기있는 오픈 소스 라이브러리를 사용하여 이미지를 다운로드 (및 저장)하는 방법을 보여주는 "Image Downloader"라는 데모 프로젝트를 만들었습니다 . 전체 소스 코드를 보거나 GitHub 에서 프로젝트 를 다운로드 할 수 있습니다 .
참고 : 아직 SDK 23+ (Marshmallow)에 대한 권한 관리를 조정하지 않았으므로 프로젝트는 SDK 22 (Lollipop)를 대상으로합니다.
내에서 결론 이 게시물의 끝에 나는 공유 할 것입니다 내 소견 내가 언급 한 이미지 다운로드의 각각의 특정 방법에 대한 적절한 사용 사례에 대한합니다.
자체 구현부터 시작하겠습니다 (게시물 끝에서 코드를 찾을 수 있음). 우선, 이것이 기본 ImageDownloader이고 그게 다입니다. 그것이하는 일은 주어진 URL에 연결하고, 데이터를 읽고, 그것을으로 디코딩하려고 시도하고 Bitmap
, OnImageLoaderListener
적절한 경우 인터페이스 콜백을 트리거하는 것 입니다. 이 접근 방식의 장점은 간단하며 진행 상황에 대한 명확한 개요를 제공합니다. 메모리 / 디스크 캐시를 유지하는 데 신경 쓰지 않으면 서 일부 이미지를 다운로드 / 표시 및 저장하는 것이 필요한 경우 좋은 방법입니다.
참고 : 이미지가 큰 경우 축소 해야 할 수 있습니다 .
-
Android DownloadManager 는 시스템에서 다운로드를 처리 할 수있는 방법입니다. 실제로 이미지뿐만 아니라 모든 종류의 파일을 다운로드 할 수 있습니다. 다운로드가 조용하고 사용자에게 표시되지 않도록하거나 사용자가 알림 영역에서 다운로드를 볼 수 있도록 할 수 있습니다. BroadcastReceiver
다운로드가 완료된 후 알림을 받도록 등록 할 수도 있습니다 . 설정은 매우 간단합니다. 샘플 코드는 링크 된 프로젝트를 참조하십시오.
(가) 사용 DownloadManager
당신은 또한 이미지를 표시하려는 경우 읽고 바로 다운로드 설정하는 대신 저장된 파일을 디코딩해야하는 것 때문에, 일반적으로 좋은 생각이 아니다 Bitmap
로 ImageView
. 은 DownloadManager
당신이 다운로드 진행 상황을 추적하는 앱도 어떤 API를 제공하지 않습니다.
-
이제 훌륭한 물건 인 도서관을 소개합니다. 메모리 / 디스크 캐시 생성 및 관리, 이미지 크기 조정, 이미지 변환 등을 포함하여 이미지를 다운로드하고 표시하는 것 이상을 수행 할 수 있습니다.
Google에서 만들고 공식 문서로 다루는 강력한 라이브러리 인 Volley 부터 시작하겠습니다 . Volley는 이미지를 전문으로하지 않는 범용 네트워킹 라이브러리이지만 이미지 관리를위한 강력한 API를 제공합니다.
Volley 요청을 관리하기 위해 Singleton 클래스 를 구현해야합니다 .
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);
기본적으로 Picasso는 디스크 / 메모리 캐시를 관리하므로 걱정할 필요가 없습니다. 더 많은 제어를 위해 Target
인터페이스를 구현하고 이를 사용하여 이미지를로드 할 수 있습니다. 그러면 Volley 예제와 유사한 콜백이 제공됩니다. 예제는 데모 프로젝트를 확인하십시오.
Picasso를 사용하면 다운로드 한 이미지에 변환을 적용 할 수 있으며 해당 API를 확장하는 다른 라이브러리 도 있습니다. 또한 RecyclerView
/ ListView
/ 에서 잘 작동합니다 GridView
.
-
Universal Image Loader 는 이미지 관리 목적을 제공하는 또 다른 매우 인기있는 라이브러리입니다. 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은 명시 적으로 지정하지 않으면 메모리 / 디스크 캐시를 유지합니다.
참고 : 저자는 2015 년 11 월 27 일 현재 더 이상 프로젝트를 유지하지 않는다고 언급했습니다.하지만 많은 기여자가 있기 때문에 Universal Image Loader가 계속 유지되기를 바랍니다.
-
Facebook의 Fresco 는 최신 버전이며 (IMO)는 이미지 관리를 새로운 수준으로 끌어 올리는 가장 진보 된 라이브러리입니다 Bitmaps
. Java 힙 (Lollipop 이전)에서 애니메이션 형식 및 점진적 JPEG 스트리밍 지원에 이르기까지 .
Fresco의 아이디어와 기술에 대한 자세한 내용은 이 게시물을 참조하십시오 .
기본적인 사용법은 아주 간단합니다. 클래스 Fresco.initialize(Context);
에서 선호하는 한 번만 호출 하면 Application
됩니다. Fresco를 두 번 이상 초기화하면 예기치 않은 동작과 OOM 오류가 발생할 수 있습니다.
Fresco는 Drawee
s를 사용 하여 이미지를 표시하므로 다음과 같이 생각할 수 있습니다 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 및 애니메이션 이미지에 대한 예제를 포함했습니다.
다음 텍스트는 내 개인적인 의견을 반영하며 가정으로 간주해서는 안됩니다.
Recycler-/Grid-/ListView
할 필요가 있고 이미지를 a 에서 사용할 계획 이없고 전체 이미지를 표시 할 필요가없는 경우 BasicImageDownloader 가 사용자의 요구에 맞아야합니다.JSON
데이터를 전송 / 수신 하고 이미지와 함께 작동하지만 앱의 주요 목적이 아닌 경우 Volley를 사용하십시오 .그것을 놓친 경우 데모 프로젝트에 대한 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;
}
}
}
Cursor
( onActivityResult()
방법에서) 에서 경로를 얻은 다음 Bitmap
해당 경로를 사용하여 만드는 것 입니다. 그리고 예, 이 이미지를 SD에 저장하려는 경우 a FileOutputStream
및 a 를 사용하지 않아도됩니다 ByteArrayOutputStream
.
나는 방금이 문제를 해결하면서 왔으며 다운로드 할 수있는 완전한 코드를 공유하고 sdcard에 저장하고 (그리고 파일 이름을 숨기고) 이미지를 검색하고 마지막으로 이미지가 이미 있는지 확인합니다. 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() ;
}
AsyncTask
의 장점에 대한 기본적인 이해도 부족합니다 (매개 변수화의 적절한 사용, 병렬 실행 ..). 자세한 내용은 아래의 예를 참조하십시오. 추신 . 어떤 이유로 든 내 자신의 코드를 홍보하기 위해 이것을 작성했다고 생각하는 사람들을 위해 : 아니요, 주어진 예제에서 볼 수있는 문제를 지적하고 있습니다.
download
방법, 특히 doInBackground
내가 사용하는 작업 방법을 자세히 살펴보십시오 . 는 IOException
에 착륙 할 catch (Throwable e)
이 결과, 블록 ImageError
반환하고, onError()
콜백이 트리거된다. ImageError
객체는 원래 스택 추적과 발생의 원인이 포함됩니다Exception
왜 그것을 다운로드하기 위해 자신의 코드가 필요합니까? 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. 이미지를 다운로드하기 전에 안드로이드 내부 저장소에 이미지 파일로 비트 맵을 저장하는 방법을 작성해 보겠습니다. 컨텍스트가 필요합니다. 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();
}
}
2. 이제 andorid의 이미지 파일에 비트 맵을 저장하는 방법이 생겼습니다. URL로 이미지를 다운로드하는 AsyncTask를 작성해 보겠습니다. 이 개인 클래스는 활동 클래스에 하위 클래스로 배치되어야합니다. 이미지를 다운로드 한 후 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 또는 이미지를 사용하려는 다른 뷰의 이미지를 설정하는 데 필요한 모든 것이 있습니다. 이미지를 저장할 때 이미지 이름을 "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 삭제됨!");
이 코드는 내 프로젝트에서 완벽하게 실행됩니다.
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를 사용하는 것이 걱정됩니다 (이미지는 100kB가 될 수 있음).
나는 Picasso를 사용했고 그것은 잘 작동했고, 위에 게시 된 것에서 약간의 변화 (아마 Picasso에 대한 업데이트)가 있습니다. 아래 코드는 나를 위해 일했습니다.
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;
}
Google이 말했듯이 지금은 매니페스트의 외부 저장소에서도 읽을 수 있음을 추가하는 것을 잊지 마십시오.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
출처 : http://developer.android.com/training/basics/data-storage/files.html#GetWritePermission