Комментарии 26
Изобрел его явно не я, да и знаю я о нем. Просто привычка работать нативно с Thread, с j2me привычка то:)
0
если настаиваете — могу и переписать под AsyncTask, таки он удобнее, соглашусь
0
Переписывать не нужно. Просто хочется взглянуть еще и на вариант с AsyncTask.
0
public void fetchImage(final Activity activity, final int cacheTime, final String url, final ImageView iView) {
if (iView != null) {
if (findObject(iView)) {
return;
}
downloaded.add(iView);
}
new AsyncTask<String, Void, Bitmap>() {
protected Bitmap doInBackground(String... iUrl) {
return downloadImage(activity, cacheTime, iUrl[0], iView);
}
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (iView != null) {
iView.setImageBitmap(result);
}
}
}.execute(new String[] { url });
}
0
извиняюсь, в комменте вышло некрасиво, исправил в статье
+1
> Activity activity — активити приложения, нужно для определения пути для хранения кешированных файлов
Так все таки нужно Activity или достаточно Context?
http://developer.android.com/reference/android/content/Context.html#getExternalCacheDir()
Так все таки нужно Activity или достаточно Context?
http://developer.android.com/reference/android/content/Context.html#getExternalCacheDir()
0
Еще можно сделать второй уровень: HashMap
В качестве ключей — URL картинок.
В качестве ключей — URL картинок.
0
Мне кажется есть некоторые нестыковки.
1. getExternalCacheDir — вернет null если, например, телефон подключен через usb как девайс или если места недостаточно — думаю приложение упадет в данном случае
2. Нет проверки размера файла и ресайза — думаю приложение упадет по переполнению буфера если попытается отобразить картинку 2048*1024
3. Как то странно (если не сказать тупо) организовано время хранения файла. Ожидал чего то вроде чтения хидеров из http заголовков и выставления времени на основании expired cashe time или как там.
4. Нет таймаута на запрос — зависнет?
5. Как справедливо замечено выше — нет HashMap c ссылками для отображения изображений, например в listview, а ведь именно там и начинаются все пляски с onLowMemoryReceived, очистки кеша, recycle и т.д.
Выглядит так, как будто данный класс не был использован в реальных проектах иначе подобные вопросы всплыли бы? Правда я просмотрел код по диагонали.
На stackoverflow можно найти более юзабельные классы для загрузки изображений и доработать напильником. А ещё лучше посмотреть как реализована работа с изображениями в GreenDroid и сразу делать хорошо
1. getExternalCacheDir — вернет null если, например, телефон подключен через usb как девайс или если места недостаточно — думаю приложение упадет в данном случае
2. Нет проверки размера файла и ресайза — думаю приложение упадет по переполнению буфера если попытается отобразить картинку 2048*1024
3. Как то странно (если не сказать тупо) организовано время хранения файла. Ожидал чего то вроде чтения хидеров из http заголовков и выставления времени на основании expired cashe time или как там.
4. Нет таймаута на запрос — зависнет?
5. Как справедливо замечено выше — нет HashMap c ссылками для отображения изображений, например в listview, а ведь именно там и начинаются все пляски с onLowMemoryReceived, очистки кеша, recycle и т.д.
Выглядит так, как будто данный класс не был использован в реальных проектах иначе подобные вопросы всплыли бы? Правда я просмотрел код по диагонали.
На stackoverflow можно найти более юзабельные классы для загрузки изображений и доработать напильником. А ещё лучше посмотреть как реализована работа с изображениями в GreenDroid и сразу делать хорошо
+1
1. Просто класс используется в приложении, которое отказывается запускаться без карты памяти, поэтому я не вводил проверку на существование карты памяти, а делается это двумя строчками ровно.
2. В основном используюю класс для иконок в ListView, и там таки размеры уж точно не нужны.
3. При таймауте должно выбить Exception и класс удалит файл кеша, если оный имеется.
4. Ну тут согласен
2. В основном используюю класс для иконок в ListView, и там таки размеры уж точно не нужны.
3. При таймауте должно выбить Exception и класс удалит файл кеша, если оный имеется.
4. Ну тут согласен
0
} catch (Exception e) {
e.printStackTrace();
}
Не айс…
0
Дальше код посмотрите:
if (bitmap == null) {
file.delete();
}
Тоесть если нет никакой картинки — удаляем
if (bitmap == null) {
file.delete();
}
Тоесть если нет никакой картинки — удаляем
0
Я про перехват Exception вместо IOException и иных проверяемых исключений которые может выбрасывать ваш код. Меня, пришедшего с .NET, очень печалит когда на яве, имеющей такую прекрасную вещь как проверяемые исключения, люди плюют на человеческую обработку.
0
Тут при любом исключении требуется только одно — ничего не делать
0
К сожалению это не так. Например проглотить OutOfMemoryError — не лучшая идея. Другие варианты — возможные ошибки вашего кода (в общем случае), которые могут остаться незамеченными, вроде NullRef и т.д
Советую прочитать как можно больше про обработку исключений. Их необдуманное использование может создать вам массу проблем.
Советую прочитать как можно больше про обработку исключений. Их необдуманное использование может создать вам массу проблем.
0
Дело в том, что я писал статью "Пишем функцию сохранения картинок на SD-карту", а не «Качаем картинки из Инета и потом куда-нибудь их сохраняем при этом кэшируя». Вероятно по этому ваши ожидания не оправдались.
С другой стороны — это же хорошо. Неоправдавшиеся ожидания привели к новой статье с дополнительными деталями и объяснениями некоторых неохваченных доселе вопросов.
Что же до моего проекта, я в нем не мудрствую лукаво, и для скачивания картинок из интернета пользуюсь специальным довольно стандартным классом (AsyncTask, да) такого вот содержания:
Этого вполне достаточно, чтобы асинхронно грузить картинки из интернета не тормозя UI.
Нужно просто создать новый класс, записать в него вышеприведенный код и сохранить его как отдельный файл в проекте. А вызывается он всего тремя строчками в коде:
С другой стороны — это же хорошо. Неоправдавшиеся ожидания привели к новой статье с дополнительными деталями и объяснениями некоторых неохваченных доселе вопросов.
Что же до моего проекта, я в нем не мудрствую лукаво, и для скачивания картинок из интернета пользуюсь специальным довольно стандартным классом (AsyncTask, да) такого вот содержания:
public class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;
public ImageDownloader(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
// эта функция качает файло
@Override
protected Bitmap doInBackground(String... params) {
url = params[0];
URL myFileUrl = null;
HttpURLConnection conn;
InputStream is;
try {
myFileUrl= new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
try {
conn = (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
return BitmapFactory.decodeStream(is);
catch (Exception e)
{
e.printStackTrace();
is = null;
conn = null;
return null;
}
}
// эта функция показывает скачанный файл в ImageView
@Override
protected void onPostExecute(Bitmap result) {
if (isCancelled()) {
result = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(result);
}
}
}
// Эта функция вызывается для того, чтобы показать пользователю что-то, пока грузится картинка.
// Например песочные часы или лучше прогрессбар
@Override
protected void onPreExecute() {
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageResource(R.drawable.icon);
}
}
}
}
Этого вполне достаточно, чтобы асинхронно грузить картинки из интернета не тормозя UI.
Нужно просто создать новый класс, записать в него вышеприведенный код и сохранить его как отдельный файл в проекте. А вызывается он всего тремя строчками в коде:
ImageView iv;
ImageDownloader downloader = new ImageDownloader(iv);
downloader.execute(pictureURL);
+1
Лучше вместо:
использовать такую конструкцию:
Тогда и кэширование будет и периодически ошибка «decode returned false» не будет возникать.
conn = (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
return BitmapFactory.decodeStream(is);
использовать такую конструкцию:
HttpGet req = null;
req = new HttpGet(url);
HttpClient _client = new DefaultHttpClient();
HttpResponse resp = (HttpResponse) _client.execute(req);
HttpEntity entity = resp.getEntity();
BufferedHttpEntity buffered_entity = new BufferedHttpEntity(entity);
InputStream is = buffered_entity.getContent();
BitmapFactory.decodeStream(is);
Тогда и кэширование будет и периодически ошибка «decode returned false» не будет возникать.
+2
То-есть для каждого ImageView класс ImageDownloader создается новый? Нехорошо конечно…
0
У вас проблемы с многопоточностью, и то что Vector засинхронизирован вас не спасёт. findObject никак не защищён от того, что во время цикла элемент может быть удылён другим потоком. И почему список downloaded это список ImageView (т.е. куда качаем), а не собственно того что мы качаем? Одна и та же картинка для разных ImageView будет качаться отдельно?
0
Использовал ваш код у себя. У меня >300 изображений грузится во время обновления. В принципе они не большие, не более 500кб. Но весь процесс происходит до ужаса долго. Каждая картинка льется по 2-3 минуты. Не в курсе что могло послужить этому причиной?
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Кеширование изображений на SD карте