Как загрузить и сохранить изображение с заданного URL-адреса в Android?
Как загрузить и сохранить изображение на Android
Ответы (10)
Редактировать от 30.12.2015 - Полное руководство по загрузке изображений
последнее крупное обновление: 31 марта 2016 г.
TL;DR, иначе говоря, хватит болтать, просто дайте мне код!!
Перейдите к нижней части этого сообщения, скопируйте
BasicImageDownloader
(версия javadoc здесь) в свой проект, реализуйте интерфейсOnImageLoaderListener
, и все готово.Примечание: хотя
BasicImageDownloader
обрабатывает возможные ошибки и предотвращает сбой вашего приложения в случае, если что-то пойдет не так, он не будет выполнять какую-либо постобработку (например, уменьшение размера) загруженногоBitmaps
.
Поскольку этот пост получил довольно много внимания, я решил полностью переработать его, чтобы люди не использовали устаревшие технологии, плохие методы программирования или просто делали глупости — например, искали «хаки» для запуска сети в основном потоке или принимать все сертификаты SSL.
Я создал демонстрационный проект под названием «Загрузчик изображений», который демонстрирует, как загружать (и сохранять) изображение, используя мою собственную реализацию загрузчика, встроенный в Android DownloadManager
, а также некоторые популярные библиотеки с открытым исходным кодом. Вы можете просмотреть полный исходный код или загрузить проект на GitHub.
Примечание. Я еще не настроил управление разрешениями для SDK 23+ (Marshmallow), поэтому проект ориентирован на SDK 22 (Lollipop).
В моем заключении в конце этого поста я поделюсь своим скромным мнением о правильном использовании каждого конкретного способа загрузки изображений. упомянул.
Начнем с собственной реализации (код вы найдете в конце поста). Прежде всего, это BasicImageDownloader и этим все сказано. Все, что он делает, это подключается к заданному URL-адресу, считывает данные и пытается декодировать их как Bitmap
, вызывая обратные вызовы интерфейса OnImageLoaderListener
, когда это необходимо. Преимущество такого подхода — он прост и у вас есть четкое представление о том, что происходит. Хороший способ, если все, что вам нужно, это загрузка/отображение и сохранение некоторых изображений, в то время как вам не нужно поддерживать кеш памяти/диска.
Примечание. В случае больших изображений может потребоваться уменьшить их масштаб а>.
--
Android DownloadManager — это способ, позволяющий системе выполнять загрузку за вас. На самом деле он способен загружать любые файлы, а не только изображения. Вы можете сделать так, чтобы ваша загрузка происходила тихо и незаметно для пользователя, или вы можете разрешить пользователю видеть загрузку в области уведомлений. Вы также можете зарегистрировать BroadcastReceiver
, чтобы получать уведомления после завершения загрузки. Настройка довольно проста, см. связанный проект для примера кода.
Использование DownloadManager
, как правило, не является хорошей идеей, если вы также хотите отобразить изображение, поскольку вам нужно будет прочитать и декодировать сохраненный файл, а не просто установить загруженный Bitmap
в ImageView
. DownloadManager
также не предоставляет вашему приложению никакого API для отслеживания хода загрузки.
--
Теперь знакомство с замечательными вещами — библиотеками. Они могут делать гораздо больше, чем просто загружать и отображать изображения, в том числе: создавать и управлять кэшем памяти/диска, изменять размер изображений, преобразовывать их и многое другое.
Я начну с Volley, мощной библиотеки, созданной Google и подпадающей под действие официального документация. Будучи сетевой библиотекой общего назначения, не специализирующейся на изображениях, Volley имеет довольно мощный API для управления изображениями.
Вам нужно будет реализовать класс Singleton для управления запросами Volley, и все готово.
Возможно, вы захотите заменить свой ImageView
на NetworkImageView
Volley, чтобы загрузка в основном стала однострочной:
((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 идеально вам подойдет.
--
Picasso от Square – это известная библиотека, которая сделает за вас всю загрузку изображений. Просто отобразить изображение с помощью 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 поддерживает кэш памяти/диска, если вы явно не укажете ему не делать этого.
Примечание: автор упомянул, что он больше не поддерживает проект с 27 ноября 2015 года. Но поскольку участников много, мы можем надеяться, что универсальный загрузчик изображений будет жить.
--
Fresco от Facebook — это новейшая и (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 и анимированных изображений в пример проекта.
Вывод - "Я узнал об отличном материале, что мне теперь использовать?"
Обратите внимание, что следующий текст отражает мое личное мнение и не должен восприниматься как постулат.
- Если вам нужно только загрузить/сохранить/отобразить некоторые изображения, не планируйте использовать их в
Recycler-/Grid-/ListView
и не нужно, чтобы вся куча изображений была готова к отображению, вам подойдет BasicImageDownloader. твои нужды. - Если ваше приложение сохраняет изображения (или другие файлы) в результате действий пользователя или автоматических действий и вам не нужно, чтобы изображения отображались часто, используйте Android DownloadManager.
- Если ваше приложение много взаимодействует с сетью, передает/получает
JSON
данных, работает с изображениями, но это не является основной целью приложения, используйте Volley. - Ваше приложение ориентировано на изображения/медиафайлы, вы хотите применить некоторые преобразования к изображениям и не хотите возиться со сложным API: используйте Picasso (Примечание: не предоставляет никакого API для отслеживания промежуточный статус загрузки) или Универсальный загрузчик изображений
- Если ваше приложение полностью связано с изображениями, вам нужны расширенные функции, такие как отображение анимированных форматов, и вы готовы читать документацию, используйте 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;
}
}
}
Cursor
(в методе onActivityResult()
), а затем создать Bitmap
с использованием этого пути. И да, вам не избежать использования FileOutputStream
и ByteArrayOutputStream
, если вы хотите сохранить это изображение на SD.
- person Droidman; 27.12.2013
Я только что решил эту проблему, и я хотел бы поделиться полным кодом, который может загружать, сохранять на SD-карту (и скрывать имя файла) и извлекать изображения, и, наконец, он проверяет, есть ли изображение. URL-адрес исходит из базы данных, поэтому имя файла может быть легко уникальным с использованием идентификатора.
первая загрузка изображений
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
(правильное использование параметризации, параллельное выполнение...). Пожалуйста, обратитесь к моим примерам ниже для деталей. P.S. для тех, кто может подумать, что я написал это для продвижения своего собственного кода по какой-либо причине: нет, я просто указываю на проблемы, которые я вижу в данном примере.
- person Droidman; 04.02.2016
download
, особенно на метод doInBackground
задачи, которую я использую. IOException
попадет в блок catch (Throwable e)
, что приведет к возврату ImageError
и запуску обратного вызова onError()
. Объект ImageError
будет содержать исходную трассировку стека и причину произошедшего Exception
- person Droidman; 04.02.2016
Зачем вам действительно нужен собственный код для его загрузки? Как насчет того, чтобы просто передать свой 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, давайте напишем 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. Для этого напишите эту строку в своем методе onCreate в своем классе Activity или в методе onClick кнопки или в других местах, которые вы считаете нужными.
new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");
Изображение должно быть сохранено в /data/data/your.app.packagename/files/my_image.jpeg, проверьте этот пост для доступа к этому каталогу с вашего устройства.
ИМХО, это решает проблему! Если вам нужны дополнительные шаги, такие как загрузка изображения, вы можете выполнить следующие дополнительные действия:
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 хорошо работает с небольшими данными в несколько килобайт. Когда я попытался использовать «BasicImageDownloader.java», Android Studio предупредила меня, что класс AsyncTask должен быть статическим, иначе могут быть утечки. Я использовал Volley в другом тестовом приложении, и оно продолжало падать из-за утечек, поэтому я беспокоюсь об использовании Volley для загрузчика изображений (изображения могут быть меньше 100 КБ).
Я использовал Пикассо, и он работал хорошо, есть небольшое изменение (вероятно, обновление Пикассо) по сравнению с тем, что было опубликовано выше. Ниже код работал для меня:
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