Pull to refresh

Как реализовать загрузку изображений в список в отдельном потоке на Android

Reading time 5 min
Views 38K
List Image Fetching
По просьбам трудящихся, статья о методе загрузки изображений в список в отдельном потоке на Android.

Задача:


Реализовать механизм загрузки изображений из Интернета и отображения их в списке. При этом загрузка изображений должна быть реализована в отдельном потоке, во избежания «зависания» UI приложения.

Реализация:


Для реализации поставленной задачи использованы стандартный виджет ListView и адаптер — ArrayAdapter. Для работы с изображениями создан helper-класс ImageManager, который имеет два метода downloadImage() и fetchImage(). Первый загружает изображений из Интернета. Второй — вызывает загрузку изображений в отдельном потоке и устанавливает результат в ImageView.


Пример испольования:


Реализацию поставленной задачи будем расматривать на примере моего проекта. И на его код я буду ссылаться в статье.
Исходники: fileshare.in.ua/3053597
APK: fileshare.in.ua/3053596

Описание реализации:


Давайте рассмотрим поподробнее каждый из методов ImageManager'а:
  1. package com.rudenko.android.ListIconFetching;
  2.  
  3. import java.io.BufferedInputStream;
  4. import java.io.IOException;
  5. import java.net.HttpURLConnection;
  6. import java.net.MalformedURLException;
  7. import java.net.URL;
  8.  
  9. import android.graphics.Bitmap;
  10. import android.graphics.BitmapFactory;
  11. import android.os.Handler;
  12. import android.os.Message;
  13. import android.util.Log;
  14. import android.widget.ImageView;
  15.  
  16. public class ImageManager {
  17.   private final static String TAG = "ImageManager";
  18.  
  19.   /** Private constructor prevents instantiation from other classes */
  20.   private ImageManager () {}
  21.  
  22.   public static void fetchImage(final String iUrl, final ImageView iView) {
  23.     if ( iUrl == null || iView == null )
  24.       return;
  25.  
  26.     final Handler handler = new Handler() {
  27.       @Override
  28.       public void handleMessage(Message message) {
  29.         final Bitmap image = (Bitmap) message.obj;
  30.         iView.setImageBitmap(image);
  31.       }
  32.     };
  33.  
  34.     final Thread thread = new Thread() {
  35.       @Override
  36.       public void run() {
  37.         final Bitmap image = downloadImage(iUrl);
  38.         if ( image != null ) {
  39.           Log.v(TAG, "Got image by URL: " + iUrl);
  40.           final Message message = handler.obtainMessage(1, image);
  41.           handler.sendMessage(message);
  42.         }
  43.       }
  44.     };
  45.     iView.setImageResource(R.drawable.icon);
  46.     thread.setPriority(3);
  47.     thread.start();
  48.   }
  49.  
  50.   public static Bitmap downloadImage(String iUrl) {
  51.     Bitmap bitmap = null;
  52.     HttpURLConnection conn = null;
  53.     BufferedInputStream buf_stream = null;
  54.     try {
  55.       Log.v(TAG, "Starting loading image by URL: " + iUrl);
  56.       conn = (HttpURLConnection) new URL(iUrl).openConnection();
  57.       conn.setDoInput(true);
  58.       conn.setRequestProperty("Connection", "Keep-Alive");
  59.       conn.connect();
  60.       buf_stream = new BufferedInputStream(conn.getInputStream(), 8192);
  61.       bitmap = BitmapFactory.decodeStream(buf_stream);
  62.       buf_stream.close();
  63.       conn.disconnect();
  64.       buf_stream = null;
  65.       conn = null;
  66.     } catch (MalformedURLException ex) {
  67.       Log.e(TAG, "Url parsing was failed: " + iUrl);
  68.     } catch (IOException ex) {
  69.       Log.d(TAG, iUrl + " does not exists");
  70.     } catch (OutOfMemoryError e) {
  71.       Log.w(TAG, "Out of memory!!!");
  72.       return null;
  73.     } finally {
  74.       if ( buf_stream != null )
  75.         try { buf_stream.close(); } catch (IOException ex) {}
  76.       if ( conn != null )
  77.         conn.disconnect();
  78.     }
  79.     return bitmap;
  80.   }
  81. }
* This source code was highlighted with Source Code Highlighter.

Метод fetchImage():

public static void fetchImage(final String iUrl, final ImageView iView);

Входные параметры:

iUrl — URL к изображению для загрузки
iView — ссылка на виджет ImageView, которому будет назначено изображение после загрузки.
Оба параметра являются обязательными.

Результат:

Функция не возвращает ничего.

Краткое описание:

Функция создает поток для загрузки изображения. На время загрузки во входной ImageView устанавливается стандартное изображение. После завершения загрузки, изображение входного ImageView обновляется загруженным.

Несколько слов о потоке: в строке 46 происходит понижение приоритета потока. Это сделано для того, что бы данный поток не забирал ресурсы необходимые для корректной работы приложения.

Метод downloadImage():

public static Bitmap downloadImage(String iUrl);

Входные параметры:

iUrl — URL к изображению для загрузки

Результат:

Изображение загруженное из интернета, либо Null — если операция не была выполнена успешно.

Краткое описание:

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

Как использовать ImageManager:

Рассмотрим на примере к статье. В методе FetchImageAdapter.getView(), для подгрузки изображений в ImageView строки списка, используется следующая строка:
ImageManager.fetchImage(android.image, holder.ib_logo);
где android.image — URL к изображению, а holder.ib_logo — ImageView строки списка.

Заключение:


Данный механизм подходит для загрузки изображения из Интернета в параллельном потоке, для любого виджета ImageView Android. Т. е. данный механизм можно использовать не только для конкретно поставленной задачи.

P. S. пользуйтесь на здоровья.
Tags:
Hubs:
+20
Comments 13
Comments Comments 13

Articles