Ожидание загрузки изображений
Как мы уже говорили в наших предыдущих статьях,
загрузка изображений из сети Internet - длительный
процесс, который в среднем идет со скоростью 1
Кбайт в секунду. Поэтому изображения загружаются
навигатором в отдельной задаче. При этом метод
getImage только создает объект класса Image, а метод
drawImage инициирует загрузку изображения и рисует
его. Причем если файл изображения имеет большую
длину, он будет появляться в окне аплета
постепенно по мере загрузки.
Однако в некоторых случаях было бы удобно
вначале загрузить изображение полностью, а лишь
затем выполнять рисование, чтобы изображение
появилось на экране сразу. Кроме того, аплет
может рисовать сразу несколько изображений в
разных местах своего окна или показывать их по
очереди в одном и том же месте для достижения
эффекта анимации.
Есть ли способ определить, когда изображение
будет загружено полностью?
Есть, и причем целых два. Один из них связан с
использованием класса MediaTracker, специально
предназначенного для этой цели и достаточно
удобного в использовании, другой основан на
переопределении одного из методов интерфейса
ImageObserver.
Применение класса MediaTracker
Для того чтобы выполнить ожидание загрузки
нескольких изображений, проще воспользоваться
классом MediaTracker, а не интерфейсом ImageObserver.
Как это сделать?
Обычно метод init аплета создает объект класса
MediaTracker с помощью конструктора и добавляет в него
все изображения, загрузки которых необходимо
дождаться.
Создание объекта класса MediaTracker
Объект класса MediaTracker создается следующим
образом:
MediaTracker mt;
mt = new MediaTracker(this);
Конструктору класса MediaTracker передается ссылка
на компонент, для которого необходимо
отслеживать загрузку изображений. В данном
случае это наш аплет, поэтому мы передаем
конструктору значение this.
Добавление изображений в объект класса MediaTracker
Далее метод init должен создать все необходимые
объекты класса Image и добавить их в объект MediaTracker
методом addImage. Ниже мы показали фрагмент кода, в
котором выполняется добавление трех
изображений:
Image img1;
Image img2;
Image img3;
img1 = getImage(getCodeBase(), "pic1.gif");
img2 = getImage(getCodeBase(), "pic2.gif");
img3 = getImage(getCodeBase(), "pic3.gif");
mt.addImage(img1 , 0);
mt.addImage(img2 , 0);
mt.addImage(img3 , 0);
В качестве первого параметра методу addImage
передается ссылка на изображение, загрузку
которого необходимо отслеживать, а в качестве
второго - идентификатор, который можно будет
использовать в процессе отслеживания. Если все,
что вам нужно, это дождаться окончания загрузки
изображений, то для второго параметра вы можете
указать нулевое значение.
Ожидание загрузки добавленных изображений
Для того чтобы убедиться, что все изображения
загружены, вы можете воспользоваться методом
waitForAll. Этот метод инициирует загрузку
изображений, а также задержит выполнение
вызвавшего потока до момента полной загрузки
всех изображений, добавленных в объект класса
MediaTracker:
try
{
mt.waitForAll();
}
catch (InterruptedException ex)
{
}
Обратите внимание, что метод waitForAll может
создавать исключение InterruptedException. Это исключение
возникает, если по какой-либо причине процесс
ожидания прерывается.
Чаще всего рисование выполняется в отдельном
потоке, поэтому метод waitForAll должен вызываться в
начале соответствующего метода run. Ниже мы
привели исходные тексты приложения ImageDrawWait, в
котором такое ожидание выполняется в методе paint,
что приводит, однако, к блокировке работы аплета
до момента загрузки всех изображений. В данном
случае это не критично, так как кроме рисования
изображений наш аплет ничего не делает, однако
более предпочтительным является выполнение
длительных процессов в отдельном потоке.
Другие методы класса MediaTracker
Какие другие полезные методы, кроме методов
addImage и waitForAll есть в классе MediaTracker?
public boolean waitForAll(long ms);
Метод waitForAll с параметром ms позволяет выполнять
ожидание в течение заданного времени. Время
ожидания задается в миллисекундах. При этом если
за указанное время все изображения были успешно
загружены, метод waitForAll возвращает значение true,
если нет - false.
Вариант метода checkAll с параметром load позволяет
проверить, завершилась ли загрузка
отслеживаемых изображений:
public boolean checkAll(boolean load);
Если значение параметра load равно true, метод
инициирует загрузку изображений.
Если при добавлении изображений методом addImage
вы использовали второй параметр этого метода для
присваивания разным группам изображений
различные идентификаторы, то с помощью метода
checkID можно дождаться завершения загрузки
отдельной группы изображений:
public boolean checkID(int id);
Есть также вариант этого метода, позволяющий
проверить загрузку группы изображений с
заданным идентификатором:
public boolean checkID(int id, boolean load);
Метод waitForID с параметрами id и ms позволяет
выполнять ожидание загрузки группы изображений
с заданным идентификатором в течении указанного
периода времени:
public boolean waitForID(int id, long ms);
Класс MediaTracker предоставляет также возможность
прослеживать сам процесс загрузки всех
добавленных в него изображений или отдельных
групп изображений с помощью методов statusAll и statusID:
public int statusAll(boolean load);
public int statusID(int id, boolean load);
В зависимости от значения параметра load эти
методы могут инициировать загрузку изображений.
Если параметр равен true, загрузка изображений
инициируется, если false - выполняется только
проверка текущего состояния загрузки.
Методы statusAll и statusID возвращают значение,
составленное из отдельных битов состояния при
помощи логической операции ИЛИ. Ниже мы
перечислили эти биты состояния и привели их
краткое описание.
Биты состояния |
Описание |
MediaTracker.LOADING |
Один или несколько отслеживаемых файлов
продолжают загружаться |
MediaTracker.ABORTED |
Загрузка одного или нескольких файлов
была прервана |
MediatTracker.ERRORED |
При загрузке одного или нескольких
файлов произошла ошибка |
MediaTracker.COMPLETE |
Загрузка всех отслеживаемых файлов
произошла полностью и успешно |
Еще четыре метода, определенных в классе
MediaTracker, связаны с обработкой ошибок:
public boolean isErrorAny();
public boolean isErrorID(int id);
public Object[] getErrorsAny();
public Object[] getErrorsID(int id);
Методы isErrorAny и isErrorID позволяют проверить,
возникла ли ошибка при загрузке, соответственно,
любого из отслеживаемых изображений или
изображений из заданной группы. Если ошибка
произошла, возвращается значение true, если нет -
значение false.
Методы getErrorsAny и getErrorsID возвращают массив
объектов, при ожидании загрузки которых
произошла ошибка. Первый из этих методов
возвращает массив для всех отслеживаемых
объектов, второй - только объектов из заданной
группы.
Применение интерфейса ImageObserver
Второй способ ожидания завершения процесса
загрузки изображений связан с интерфейсом
ImageObserver:
Биты флагов для параметра infoflags метода imageUpdate
public final static int ABORT;
public final static int ALLBITS;
public final static int ERROR;
public final static int FRAMEBITS;
public final static int HEIGHT;
public final static int PROPERTIES;
public final static int SOMEBITS;
public final static int WIDTH;
Метод imageUpdate
public abstract boolean
imageUpdate(Image img, int infoflags,
int x, int y, int width, int height);
Как видите, в интерфейсе ImageObserver определен
единственный метод imageUpdate и набор битовых флагов
для этого метода.
Класс Component, от которого происходит класс Applet,
реализует интерфейс ImageObserver:
public abstract class java.awt.Component
extends java.lang.Object
implements java.awt.image.ImageObserver
{
. . .
}
Этот интерфейс используется для отслеживания
процесса загрузки и перерисовки изображений и
других компонент, расположенных внутри
компонента. В частности, он используется для
отслеживания загрузки и рисования растровых
изображений в окне аплета, чем мы и
воспользуемся.
В процессе загрузки вызывается метод imageUpdate,
поэтому чтобы отслеживать загрузку изображений,
наш аплет должен переопределить этот метод.
Процедура ожидания загрузки изображений
достаточно проста.
Прежде всего, аплет должен передать в последнем
параметре методу drawImage ссылку на интерфейс
ImageObserver, который будет применяться для
отслеживания процесса загрузки:
g.drawImage(Img, x, y,
width, height, this);
Здесь в качестве ссылки на интерфейс ImageObserver мы
передали значение this. При этом будет применен
интерфейс нашего аплета. Соответственно, нам
нужно определить в классе аплета метод imageUpdate,
который будет вызываться в процессе загрузки
изображений.
Ниже мы привели возможный вариант реализации
этого метода:
public boolean imageUpdate(
Image img, int flags,
int x, int y, int w, int h)
{
// Проверяем, все ли
// биты изображения загружены
fAllLoaded = ((flags & ALLBITS) != 0);
// Если все, перерисовываем окно
if(fAllLoaded)
repaint();
// Если все биты загружены,
// дальнейшие вызовы
// метода imageUpdate не нужны
return !fAllLoaded;
}
Через первый параметр img методу imageUpdate
передается ссылка на изображение, загрузка
которого отслеживается.
Параметр flags отражает состояние процесса
загрузки.
Через остальные параметры x, y, w и h передаются,
соответственно, координаты и размеры
изображения.
Основное, что должен делать метод imageUpdate для
отслеживания процесса загрузки - это проверять
флаги flags, дожидаясь установки нужных флагов.
Флаги определены следующим образом:
public final static int WIDTH;
public final static int HEIGHT = 2;
public final static int PROPERTIES = 4;
public final static int SOMEBITS = 8;
public final static int FRAMEBITS = 16;
public final static int ALLBITS = 32;
public final static int ERROR = 64;
public final static int ABORT = 128;
Ниже мы привели краткое описание перечисленных
флагов.
Флаг |
Описание |
WIDTH |
Изображение загружено настолько, что
стала доступна его ширина. Значение ширины
изображения можно получить из параметра w метода
imageUpdate |
HEIGHT |
Аналогично предыдущему, но для высоты
изображения. Высоту изображения можно получить
из параметра h метода imageUpdateimageUpdate |
PROPERTIES |
Стали доступны свойства изображения,
которые можно получить методом getProperty класса Image.
В нашей книге мы опустили описание этого метода |
SOMEBITS |
Стали доступны биты изображения для
рисования в масштабе. Через параметры x, y, h и w
передаются координаты и размеры прямоугольной
области, которая ограничивает загруженную часть
изображения |
FRAMEBITS |
Загружен очередной фрейм изображения,
состоящего из нескольких фреймов. Параметры x, y, h
и w следует игнорировать |
ALLBITS |
Изображение загружено полностью.
Параметры x, y, h и w следует игнорировать |
ERROR |
При загрузке произошла ошибка |
ABORT |
Загрузка изображения была прервана или
отменена |
Анализируя состояние флагов, метод imageUpdate может
следить за ходом загрузки изображений,
отображая, например, процент завершения процесса
загрузки или выполняя какие-либо другие
действия.
Если вам нужно только дождаться завершения
процесса загрузки, достаточно использовать флаг
ALLBITS. Для проверки ошибок воспользуйтесь флагами
ERROR и ABORT.
|