Pull to refresh

Comments 26

Изобрел его явно не я, да и знаю я о нем. Просто привычка работать нативно с Thread, с j2me привычка то:)
если настаиваете — могу и переписать под AsyncTask, таки он удобнее, соглашусь
Переписывать не нужно. Просто хочется взглянуть еще и на вариант с AsyncTask.
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 });
}
извиняюсь, в комменте вышло некрасиво, исправил в статье
Еще можно сделать второй уровень: HashMap
В качестве ключей — URL картинок.
Парсер куда-то потерял generic, там было HashMap<String, SoftReference<Bitmap>>
Тут дело не в картинках, а как я привел пример в статье: для ListView метод будет вызываться несколько раз для одного и того-же ImageView, соответственно будет плодится куча потоков с загрузкой одной и той же картинки
Мне кажется есть некоторые нестыковки.
1. getExternalCacheDir — вернет null если, например, телефон подключен через usb как девайс или если места недостаточно — думаю приложение упадет в данном случае
2. Нет проверки размера файла и ресайза — думаю приложение упадет по переполнению буфера если попытается отобразить картинку 2048*1024
3. Как то странно (если не сказать тупо) организовано время хранения файла. Ожидал чего то вроде чтения хидеров из http заголовков и выставления времени на основании expired cashe time или как там.
4. Нет таймаута на запрос — зависнет?
5. Как справедливо замечено выше — нет HashMap c ссылками для отображения изображений, например в listview, а ведь именно там и начинаются все пляски с onLowMemoryReceived, очистки кеша, recycle и т.д.

Выглядит так, как будто данный класс не был использован в реальных проектах иначе подобные вопросы всплыли бы? Правда я просмотрел код по диагонали.

На stackoverflow можно найти более юзабельные классы для загрузки изображений и доработать напильником. А ещё лучше посмотреть как реализована работа с изображениями в GreenDroid и сразу делать хорошо
1. Просто класс используется в приложении, которое отказывается запускаться без карты памяти, поэтому я не вводил проверку на существование карты памяти, а делается это двумя строчками ровно.
2. В основном используюю класс для иконок в ListView, и там таки размеры уж точно не нужны.
3. При таймауте должно выбить Exception и класс удалит файл кеша, если оный имеется.
4. Ну тут согласен
Ой, третий пункт это четвертый, а четвертый это пятый.
3. Иконки в проекте разделены на несколько групп, одни не меняются годами, другие раз в месяц, остальные вообще динамическиее. Поэтому все указывается в секундах
} catch (Exception e) {
e.printStackTrace();
}


Не айс…
Дальше код посмотрите:

if (bitmap == null) {
file.delete();
}

Тоесть если нет никакой картинки — удаляем
Я про перехват Exception вместо IOException и иных проверяемых исключений которые может выбрасывать ваш код. Меня, пришедшего с .NET, очень печалит когда на яве, имеющей такую прекрасную вещь как проверяемые исключения, люди плюют на человеческую обработку.
Тут при любом исключении требуется только одно — ничего не делать
К сожалению это не так. Например проглотить OutOfMemoryError — не лучшая идея. Другие варианты — возможные ошибки вашего кода (в общем случае), которые могут остаться незамеченными, вроде NullRef и т.д

Советую прочитать как можно больше про обработку исключений. Их необдуманное использование может создать вам массу проблем.
Дело в том, что я писал статью "Пишем функцию сохранения картинок на SD-карту", а не «Качаем картинки из Инета и потом куда-нибудь их сохраняем при этом кэшируя». Вероятно по этому ваши ожидания не оправдались.
С другой стороны — это же хорошо. Неоправдавшиеся ожидания привели к новой статье с дополнительными деталями и объяснениями некоторых неохваченных доселе вопросов.

Что же до моего проекта, я в нем не мудрствую лукаво, и для скачивания картинок из интернета пользуюсь специальным довольно стандартным классом (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);

Лучше вместо:

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» не будет возникать.
То-есть для каждого ImageView класс ImageDownloader создается новый? Нехорошо конечно…
У меня один ImageView :)

А если их много — ну хочешь, можешь им pool сделать, это же AsyncTask, т.е. свой поток, хоть и специально сильно облегченный. Хочешь сразу во много потоков картинки грузить — создавай каждый раз новый, хочешь грузить только то, что видно юзеру — делай пул.
У вас проблемы с многопоточностью, и то что Vector засинхронизирован вас не спасёт. findObject никак не защищён от того, что во время цикла элемент может быть удылён другим потоком. И почему список downloaded это список ImageView (т.е. куда качаем), а не собственно того что мы качаем? Одна и та же картинка для разных ImageView будет качаться отдельно?
Опять же, этот класс я использую для элементов списка, метод fetchImage может вызываться несколько раз для одной и того-же ImageView, Vector создан исключительно для этого
Использовал ваш код у себя. У меня >300 изображений грузится во время обновления. В принципе они не большие, не более 500кб. Но весь процесс происходит до ужаса долго. Каждая картинка льется по 2-3 минуты. Не в курсе что могло послужить этому причиной?
Sign up to leave a comment.

Articles

Change theme settings