учебники, программирование, основы, введение в,

 

Работа флэш-программ в Internet

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

  1. Если мы описываем метод класса, то имя класса будем указывать в угловых скобках.
  2. Необязательные параметры будем писать в квадратных скобках.

Например, запись
<ClassName>.methodName(parametr1 [, parametr2]);

обозначает, что метод по имени methodName принадлежит классу ClassName (и должен вызываться у объектов этого класса). Аргумент parametr1 передавать обязательно (иначе метод сработает неверно или не сработает вообще), а аргумент parametr2 в принципе можно и опустить.
Загрузка веб-страниц из Flash MX
Сперва рассмотрим важную возможность флэш-роликов, о которой мы раньше почти не говорили. Мы имеем в виду возможность загружать документ с заданным URL в заданное окно браузера. Делается это с помощью глобальной функции getURL или метода getURL класса MovieClip. Синтаксис вызова у них практически одинаков и имеет следующий вид:
getURL(url [, window [, variables]]);
<MovieClip>.getURL(url [,window, variables]);

Первый параметр - это URL того документа, который вы хотите загрузить. Это может быть как html-документ, так и просто *.swf-файл или картинка. Допускаются не только полные, но и относительные пути. По умолчанию относительный путь отсчитывается от html-документа, в который был загружен ваш ролик. О том, как поменять это умолчание, см. параграф "Изменение текущей директории (атрибут BASE)". Учтите, что вы можете загружать дополнительные файлы только из того же домена, из которого была исходная страница.
Второй параметр (необязательный) - это имя окна (фрейма), в которое должна быть загружена страница. Если вы его не указываете, то загрузка произойдет в текущее окно (фрейм). Есть четыре предопределенных значения этого аргумента; сейчас мы поясним, что значит каждое из них.
_self - текущий фрейм текущего окна.
_blank - новое окно.
_parent - родительский фрейм (по отношению к текущему).
_top - фрейм верхнего уровня в текущем окне.
Имейте в виду, что если вы в качестве имени окна передаете "_self" или не передаете ничего (то есть хотите загрузить страницу в то окно, в котором сейчас находится ваш флэш-ролик), то прежняя страница (вместе с вашим роликом) будет выгружена. Это произойдет даже в том случае, если вы загрузите повторно текущую страницу с вашим роликом - ролик (вместе с флэш-плеером) будет выгружен, а потом загружен в начальном состоянии. Если вы хотите сохранять состояние ролика, используйте SharedObjects (см. одноименный параграф).
Третий аргумент (также необязательный) - это имя метода, которым будут посланы на сервер переменные. Вот здесь стоит задержаться: во-первых, информация, которую мы хотим вам сейчас сообщить вовсе не очевидна; во-вторых, она пригодится вам в нескольких следующих параграфах.
Итак, веб-страница, которую вы хотите показать, может быть получена как из некоего локального хранилища, так и с веб-сервера. В последнем случае она могла храниться на сервере статическим образом, а могла быть сгенерирована им по вашему запросу. Так вот, очень часто нужно передать на сервер какую-то информацию (скажем, о действиях пользователя), чтобы сгенерированная сервером страница была адекватна текущей ситуации. В настоящей лекции вы узнаете несколько способов это сделать; сейчас мы опишем самый старый и заслуженный. Состоит данный способ в том, что все поля некоторого объекта упаковываются в строчку специального вида и отправляются на сервер. (О том, как именно происходит упаковка, мы расскажем в следующем параграфе). Причем есть два способа отправить эту строчку на сервер. Первый - прикрепить ее в конце URL запрашиваемого документа (вы наверняка встречали URL такого вида, когда после вопросительного знака идет набор параметров). Второй - послать в отдельном HTTP-пакете. Первый способ годится, если посылаемая на сервер информация не очень объемиста. Второй годится всегда. Чтобы переменные были отправлены первым способом, вам в качестве третьего аргумента getURL нужно написать "GET", а чтобы вторым - "POST". Если же вы опустите третий аргумент при вызове getURL, переменные не будут отправляться на сервер вовсе (при этом на сервер пойдет типа GET, только без переменных, присоединенных к строке URL).
Остался один важный вопрос, который мы еще не рассмотрели. Поля какого именно объекта пересылает на сервер функция getURL? Если речь идет о методе MovieClip, то ответ очевиден: у какого объекта метод вызвали, у того и возьмут поля для отправки. А если вызвана глобальная функция? В таком случае будут отправлены переменные того клипа, в кадре которого расположен ваш код. Например, если вы писали код прямо в корневом клипе, то и отправятся на сервер все переменные из _root.
Ко всему вышесказанному нужно сделать примечание: есть три случая, когда Флэш демонстрирует нам слегка неожиданное поведение. Неожиданность первая случается, если вы сказали посылать переменные методом POST, но в объекте, из которого надо слать переменные, не нашлось ни одного поля (доступного для for...in-перебора), чтобы его можно было послать. Тогда Флэш неожиданно решает проявить интеллект и оптимизировать ваш запрос, послав его методом GET, а не POST. Спору нет, это может увеличить скорость работы, но вдруг сервер в данном случае рассчитывает только на POST-запрос? Если такое поведение действительно окажется неудобным, придется завести в вашем объекте фиктивную переменную для отправки ее на сервер. Неожиданность вторая произойдет, если вы вызовете метод getURL у объекта типа MovieClip (или его наследника), который был создан при помощи команды new MovieClip() вместо attachMovie, createEmptyMovieClip и т.п. (то есть ваш объект не встроен в дерево клипов). В этом случае переменные будут отправлены из клипа, в кадре которого написан текущий кусок кода, а вовсе не из того клипа, у которого вы вызвали getURL. Неожиданность третья: если вы тестируете ваш ролик из-под встроенного во Флэш МХ плеера (того, что запускается по нажатию Ctrl+Enter), то вы обнаружите, что getURL всегда посылает на сервер запрос типа GET, независимо от того, какой тип запроса вы указали в третьем аргументе. К счастью, в браузере все работает как надо.

URL-кодированные строки переменных

Как мы уже говорили, при отправке на сервер переменные специальным образом упаковываются в строчку. Нужно ли нам знать о том, как именно выглядит такая строка? Оказывается, да, поскольку в том же самом виде сервер может пересылать какие-то данные нашему ролику по его запросу. Более того, данные не обязательно должны генерироваться сервером непосредственно по запросу, они могут быть просто помещены в файл, который ваш ролик будет загружать. Какие именно методы классов и глобальные функции могут загружать данные, мы обсудим чуть позже, а пока разберемся с форматом.
Итак, данные (говоря иначе, параметры), отправляемые на сервер и приходящие с сервера, имеют следующий вид: строка с данными разбита на небольшие блоки, каждый из которых описывает имя и значение одного параметра (переменной). Переменная и ее значение разделяются знаком равенства (=). Блоки отделяются друг от друга символом &. В переменных и их значениях допускается использовать только латинские буквы (прописные и строчные) и цифры. Всевозможное знаки препинания (в том числе подчеркивание и пробел), а также русские буквы (или другие символы из верхний части ASCII-таблицы) заменяются на их шестнадцатеричный ASCII-код, перед которым ставится знак %. Например, если на сервер посылаются переменные а (имеющая значение 14), b (равная 17) и programName (значением которой является строка "Flash MX"), то эти данные будут скомпонованы в строку "a=14&b=17&program=Flash%20MX". Этот способ кодирования (иногда называемый url-кодированием) является стандартным и данные, закодированные так, имеют тип MIME application/x-www-form-urlencoded. (На всякий случай поясним, что типом MIME называется представленная в определенном стандартном виде информация о том, как именно веб-сервер, браузер, почтовый клиент, и прочие интернет-ориентированные программы должны воспринимать некоторую порцию данных. Аббревиатура MIME расшифровывается как Multipurpose Internet Mail Extensions - трудно представить, но когда-то данные, о которых нужно было специально сообщать, как их воспринимать, попадались в основном в аттачментах электронной почты.)
Операция замены символов, которые не являются латинскими алфавитно-цифровыми, на их шестнадцатеричный код, предваренный процентом, в случае надобности может быть выполнена и внутри флэш-программы при помощи функции escape (string_to_escape). Обратное преобразование выполняется функцией unescape (string_to_unescape). Так что при помощи функции escape вы можете посмотреть на то, во что превращаются ваши строки при посылке на сервер. Разумеется, бывают случаи, когда применять эти функции приходится не только из любопытства. В частности, бывает, что нужно сформировать внутри вашего ролика целый URL вместе с параметрами, передаваемыми в конце URL (после вопросительного знака) GET-методом. И потом этот URL еще куда-нибудь переслать для дальнейшей обработки. Вот тогда и пригождается функция escape. На всякий случай выскажем теперь в явном виде то, что ранее в этом абзаце молчаливо подразумевалось: при отправке переменных на сервер вызывать escape не нужно, все делается автоматически.
Наконец, пара полезных советов на тот случай, если вы захотите поместить параметры в файл, который будет загружаться вашим роликом (о том, какие функции это делают, поговорим далее).
Во-первых, хотя формат остается в общих чертах тем же, ограничения гораздо слабее. А именно, в значениях переменных допускается использование русских букв, пробелов, знаков пунктуации и даже переводов строк. Фактически, проблема возникнет лишь в том случае, если в значении переменной встретятся амперсанд (&), процент или знак плюс, который используется в url-кодированных строках для замены пробела (сокращение вместо %20). Вместо них все-таки придется поставить процент и шестнадцатеричный код. Есть также тонкость, связанная с использованием русского (или другого национального) алфавита: вам придется сохранять файл в Unicode (годится и UTF-8), иначе нужные символы не прочитаются.
Во-вторых, тот факт, что Флэш нормально воспринимает практически все символы в значении переменной (даже без специального кодирования) способен доставить некоторые неприятности, если вы захотите аккуратно отформатировать ваши переменные в столбик. Переводы строк Флэш воспримет как части переменных, что может довольно сильно мешать. Придется либо вручную отрезать эти переводы строк внутри флэш-программы, либо применить следующий трюк: в конце строк поставить амперсанды, как и в начале. Получится нечто вроде

&a=14&
&b=17&
&programName=Flash MX&
    

Вот теперь все переменные будут восприняты правильно.

Загрузка дополнительных роликов

Вы уже знаете, как удобно пользоваться attachMovie для динамической загрузки клипа.
А иногда бывает очень удобно загрузить внешний ролик целиком. Это может понадобиться для совершенно разных вещей, например, для создания сложных предзагрузчиков, которые мы рассмотрим далее в этой лекции. В качестве другого примера использования загрузки внешних роликов можно привести флэш-оболочку для просмотра нескольких более-менее однородных роликов.

Как загрузить внешний ролик

Во Flash MX применяются два похожих способа загрузки роликов: loadMovie и loadMovieNum.
Метод loadMovie предназначен для загрузки внешнего ролика внутрь клипа. Синтаксис его такой:

<MovieClip>.loadMovie (url [,variables]);
        

Здесь url - это URL, откуда флэш-плеер может скачать *.swf-файл с загружаемым роликом (это может быть, например, относительный URL-путь к файлу, лежащему рядом, или обращение к web-серверу по HTTP).
Variables - необязательный параметр, обозначающий способ отправки переменных ("GET" или "POST") на сервер, его следует указывать, если действительно нужно отправить все переменные из клипа, у которого вызван метод, на web-сервер. Нельзя отправить какую-то одну переменную, отправлены будут непременно все (доступные для перебора for...in) значения переменных из данного клипа. Отправка переменных происходит в виде url-кодированной строки (см. предыдущий параграф).
Следить за процессом загрузки ролика можно, используя методы класса MovieClip getBytesLoaded(), getBytesTotal() и его же свойства _framesloaded и _totalframes. То есть вы можете сравнивать количество загруженных байтов или кадров с их полным количеством и делать отсюда соответствующие выводы. Остается лишь понять, когда именно вызывать вышеописанные функции (или просматривать содержимое свойств). Делать это в каждом кадре не оптимально. К счастью, существует событие класса MovieClip под названием onData. Подписавшись на это событие (то есть, определив в вашем классе или объекте функцию с именем onData) вы сможете узнавать о том, что пришла очередная порция данных загружаемого ролика.
Парный метод для loadMovie - unloadMovie, с помощью которого можно выгрузить ролик из клипа. После выгрузки клип становится абсолютно пустым, независимо от того, что в нем было раньше.
Аналогичные действия можно выполнить при помощи глобальной функции loadMovie, которая имеет синтаксис:

loadMovie(url, target [, variables]);
        

В этом случае клип, в который происходит загрузка, указывается в параметре target в виде строчки, описывающей путь к нему. В этом случае, как мы уже говорили, описывая свойство _target, точки заменяются слэшами. Например, клип _level1.car.wheel следует описывать как "_level1/car/wheel". Разница по сравнению с методом MovieClip.loadMovie состоит в том, что переменные на сервер посылаются из того клипа, в кадре которого была вызвана функция (а не из клипа, в который происходит загрузка нового ролика).
Рассмотрим теперь второй способ загрузки внешних роликов.
Глобальная функция loadMovieNum позволяет загрузить внешний ролик в уровень (level) флэш-плеера.
Напомним, что во флэш-плеере можно использовать произвольное количество уровней, каждый из которых определяет свое дерево владения клипов. Первый уровень называется _level0, он же _root, если ролик загружен "естественным" образом (флэш-плеером, а не с помощью loadMovie или loadMovieNum).
Не путайте эти уровни (level) с уровнями depth в клипах, которые используются для правильного расположения клипов по z-оси, это немного другое понятие, хоть уровни level тоже влияют на вертикальное расположение, но не клипов, а роликов. На определенный уровень depth в клипе можно динамически поместить объект с помощью attachMovie, в уровень же level можно загрузить только целый ролик.
Вернемся к функции loadMovieNum. Ее синтаксис таков:

loadMovieNum (url, level [,variables]);
        

Параметры url и variables имеют здесь то же назначение, что и в loadMovie, а level - это номер уровня (level), в который нужно загрузить внешний ролик. Парный метод loadMovieNum - unloadMovieNum. Если вы укажете значение параметра variables (разрешены значения "GET" или "POST"), то на сервер будут отправлены все видимые переменные, которые имеются в клипе, из кадра коего вызвана функция.
В целом loadMovieNum работает абсолютно аналогично loadMovie, какой из них использовать в конкретном случае - решать вам. Хочется отметить одно интересное свойство loadMovieNum: переменные _levelN (за исключением _level0) до применения loadMovieNum не определены, но после загрузки в соответствующий уровень (level) ролика они становятся доступны для использования.
Наконец, упомянем про ряд особенностей работы рассмотренных здесь функций. (Часть из этих особенностей присуща и функции getURL и уже обсуждалась в связи с ее работой.) Особенность первая: запросы оптимизируются, то есть если не нужно посылать ни одной переменной, то пойдет запрос типа GET независимо от того, что вы указали. Особенность вторая: если вы вызываете метод MovieClip.loadMovie, то нужно, чтобы ваш клип был корректно встроен в дерево клипов (например, с помощью attachMovie, регистрации классов и пр.), а не просто создан с помощью new. В противном случае метод сработает так, как будто он вызван у того клипа, в кадре которого написан код. Особенность третья: для глобальной функции loadMovie путь к клипу, в который будет происходить загрузка ролика, обязательно должен быть корректным (вести к существующему клипу), иначе функция loadMovie вовсе не сработает. (Нужно заметить, что пути наподобие "_level1", "_level2" и т.п. считаются корректными даже в том случае, когда в соответствующие уровни еще не загружены ролики.) Вышеописанное поведение, кстати, отличается от того случая, когда клип указан корректно, а вот с сервера никакого ролика, который должен быть в него загружен, не присылается. В этом случае предыдущее содержимое клипа все равно будет выгружено из него...

_root, _level и динамическая загрузка роликов

Если вы используете loadMovie или loadMovieNum, вас могут подстерегать проблемы.
Представьте себе, что у вас есть ролик myMovie, в котором лежит текстовое поле textField, а в первом кадре написан такой код:

_level0.textField.text = "my text";
        

Эта программа, разумеется, выводит в текстовом поле "my text".
Попробуем сделать загрузчик для такого ролика.
Сделаем новый флэш-ролик и в первом его кадре напишем:

loadMovieNum ("myMovie.swf", 1);
        

Как вы думаете, что выведет такая программа? Ничего.
В чем же дело? Если вы немного позанимаетесь отладкой, то обнаружите, что объекта "_level0.textField" нет. Дело в том, что при написании ролика myMovie вы предполагали, что _level0 - это именно то место, в котором лежит текстовое поле, а оказывается - нет. Теперь "то самое место" - это _level1, в который мы загрузили ролик myMovie.
Наш совет: не используйте без особой надобности переменные _levelN. Во Flash MX специально существует "относительная" переменная _root, которая всегда указывает на относительный корень дерева владения клипов.
Единственное оправданное обращение к переменным _level - это сознательная организация взаимодействия между роликами, которой тоже не следует злоупотреблять, чтобы не увеличивать количество зависимостей между ними.
Обсудим еще один вопрос.
Что произойдет, если загрузить ролик непосредственно в _level0? Это можно сделать, например, так: loadMovieNum (url, 0) или _level0.loadMovie (url).

Он полностью заместит собой исходный ролик, а последний выгрузится и перестанет существовать.

Загружаем переменные аналогично роликам

Во Флэш МХ существует несколько функций, предназначенных для загрузки переменных с сервера. Вот те из них, которые аналогичны функциям загрузки роликов.

<MovieClip>.loadVariables (url [,variables]);
loadVariables (url, target [, variables]);
loadVariablesNum (url, level [, variables]);
        

Как вы видите, их синтаксис полностью аналогичен синтаксису метода MovieClip.loadMovie и глобальных функций loadMovie и loadMovieNum, о которых мы писали ранее. И работают эти функции вы также совершенно аналогично. Единственная разница - что загружают в соответствующие клипы или уровни не ролики, а переменные.
Тонкости, связанные с оптимизацией запроса (заменой POST на GET, если не посылаются переменные), встраиванием клипа в дерево (для метода MovieClip.loadMovie) и неверным указанием адреса загрузки (функция вовсе не срабатывает) остаются в точности такими же при загрузке переменных, как и при загрузке клипов.
А что происходит с уже имеющимися в клипе переменными при загрузке переменных туда? Абсолютно то же самое, что и при попытке "вручную" записать туда переменные с такими же значениями. То есть если переменных не было - они создаются, если были - их значения меняются (но лишь в том случае, когда эти переменные не защищены от записи).
Но как же узнать, что все переменные загрузились? Подпишите клип, в который приходят переменные, на событие onData (создайте в нем функцию с таким именем). На всякий случай (если вы ожидаете большой объем данных, который может придти несколькими порциями) можете устроить так, чтобы в самом конце списка переменных сервер присылал вам переменную endOfLoading со значением true. И по событию onData проверять, установилось ли endOfLoading в true, или еще нет.


Рекомендуемый способ загрузки переменных
Только что мы говорили о возможности загружать с сервера или из файлов переменные. Например, вы можете сделать ini-файл и задавать в нем, размер шрифта или язык. Правда, чтобы отследить, что загрузка переменных закончилась, нам пришлось использовать событие onData класса MovieClip (и, напомним, клип должен был быть встроен в общее дерево клипов). Но нет ли какого-нибудь способа загрузить переменные в какой-нибудь "легкий" объект, который мы просто создаем при помощи new и больше ни о чем не заботимся? Оказывается, такой способ есть.
Начиная с Flash версии 6 существует объект LoadVars, который позволяет загрузить переменные, используя, URL (опять же, это может быть относительный путь к лежащему "рядом" файлу или HTTP-запрос). Заодно этот объект позволяет более удобным способом отследить, что загрузка переменных произошла.
Простейшая схема использования LoadVars такая:
  1. создать объект LoadVars;
  2. определить и записать в поле onLoad созданного вами объекта callback-функцию, вызываемую после окончания загрузки переменных; все переменные будут доступны как поля объекта LoadVars, то есть через ссылку this;
  3. вызвать метод load объекту LoadVars для инициирования загрузки переменных.

Приведем пример использования LoadVars, в котором из файла "settings.ini" загружаются имя шрифта и текущий используемый язык.
var myLoadVars = new LoadVars();              //создаем объект LoadVars
myLoadVars.onLoad = function () {     //определяем callback-метод
globalStyleFormat.face = this.font;   //устанавливаем шрифт
globalStyleFormat.applyChanges();
_global.localizer.setLocale (this.language); //устанавливаем язык
// предполагается, что объект localizer вы уже описали
// где-то в другом месте
}
myLoadVars.load("settings.ini");

В этом примере мы использовали метод load. Это значит, что никакие переменные на сервер не посылались. В том случае, когда их посылать не нужно, этот метод (имеющий всего один аргумент - URL, откуда загружаются переменные) и впрямь является оптимальным. Если же надо послать переменные на сервер, используйте метод sendAndLoad. Этот метод имеет следующий синтаксис:
<LoadVars>.sendAndLoad(url, targetObject [,method]);

Здесь targetObject - это ссылка на объект типа LoadVars, в который следует загрузить переменные. На сервер же будут посланы, как обычно, переменные того объекта, для которого вызвана функция. Еще раз обратим ваше внимание, что targetObject - обычная ссылка, а не строковый путь (который все равно работает только для клипов). Все-таки LoadVars - это довольно современный способ работы с переменными, он появился (в отличие от старых глобальных функций loadVariables и пр.) только во Флэш МХ. Наконец, третий аргумент, как обычно, описывает метод, которым следует слать переменные. Если метод не указывать, то переменные все равно посылаются - ведь мы явным образом скомандовали их слать. А вот метод посылки переменных по умолчанию - это, как ни странно, POST. Впрочем, правило "оптимизации метода" работает и здесь: если в объекте нет ни одной переменной, которую можно было бы послать, то на сервер уходит запрос типа GET.
Наконец, в классе LoadVars есть еще метод, который аналогичен функции getURL. Это метод send. Вот его описание:
<LoadVars>.send(url, target [, method]);

Здесь, в отличие от метода sendAndLoad, второй аргумент target - это не ссылка, а строка, и значение этого аргумента совсем другое. Данная строка представляет собой имя окна или фрейма браузера, в который нужно загрузить веб-страницу (или информацию другого типа), которую пришлет сервер. Если это имя неизвестно серверу, он открывает новое окно (можно также использовать предопределенные имена _self, _top, _parent и _blank, описанные в параграфе, посвященном функции getURL). Несмотря на то, что написано в онлайн-документации Флэш МХ, данный аргумент не является необязательным. Если его опустить (или заменить на null), сервер вовсе не получает запроса, хотя сам метод send и возвращает при этом true.
Третий аргумент, как обычно, - это метод посылки переменных. Методом по умолчанию является POST, но правило "оптимизации метода" действует и здесь - если нечего слать, то будет применен метод GET.
Интересно, что данный метод, как и функция getURL, имеет забавную особенность: при тестировании во встроенном в интегрированную среду Флэш МХ флэш-плеере, запрос всегда посылается методом GET, какой бы метод мы ни указали. Но из браузера все работает правильно.
И, кстати, обратим внимание на то, что в отличие от рассмотренных ранее методов, которые что-либо шлют на сервер или получают с него, методы LoadVars возвращают булевский результат вызова. Этот результат может быть равен false например в том случае, когда аргумент targetObject метода sendAndLoad не указывает на объект типа LoadVars (тогда и на сервер ничего не посылается).

Предзагрузчики

Первое, что приходит в голову, когда речь идет о загрузке флэш-роликов через Интернет, - это вопрос "сколько ролик будет загружаться и сколько этого придется ждать пользователю?". Одно из лучших решений этой проблемы - показать пользователю красивую картинку "Loading..." (возможно, с какой-то "легкой" анимацией) и предоставить информацию о том, сколько процентов основного ролика уже загружено. Для этого и предназначены предзагрузчики (preloaders).

Как сделать простой предзагрузчик

Что нужно для того, чтобы сделать предзагрузчик? Две вещи:

  • механизм, позволяющий узнать, какой процент ролика уже загрузился;
  • механизм, позволяющий организовать ожидание, пока не загрузился весь ролик.

По поводу первого механизма, здесь есть два варианта:

  1. можно использовать свойства MovieClip _framesloaded и _totalframes;
  2. можно использовать методы MovieClip getBytesLoaded() и getBytesTotal().

В зависимости от того, о чем предпочтительнее узнать: о проценте загруженных кадров или о проценте загруженных байтов, можно выбрать любой из этих вариантов. В любом случае, путем сопоставления этих двух параметров можно получить нужную информацию - процент загрузки.
Что касается второго механизма, то вы уже, наверное, догадались, что здесь можно использовать трехкадровый цикл.
Пример.
Пусть в первом кадре у вас нарисована красивая картинка и лежит текстовое поле с именем textField, предназначенное для вывода в него процента загрузки.
Поместите в первый кадр слоя Actions такой код:

textField.text = "Loading: " + _framesloaded / _totalframes;
        

А во второй кадр слоя Actions - такой:

if ((_framesloaded / _totalframes) < 1) gotoAndPlay (1);
        

Вот и весь предзагрузчик. Как только отношение _framesloaded / _totalframes достигнет 1, мы выйдем из цикла и перейдем к основной анимации, расположенной дальше второго кадра.
Отметим еще раз, что, используя _framesloaded, _totalframes, getBytesLoaded() и getBytesTotal(), можно также следить за процессом загрузки роликов, загружаемых через loadMovie. Как мы уже говорили раньше, это никак не относится к runtime-shared символам, о процессе загрузки которых ничего узнать нельзя.
Не забывайте также, что если вы поставите у символа библиотеки галочку Export in first frame в параметрах символа (которую обязательно нужно поставить, если вы хотите динамически создавать экземпляры этого символа с помощью attachMovie()), он будет загружен в самом первом фрейме, из чего следует, что предзагрузчик не будет работать, как предполагалось.

Внешний предзагрузчик

Что же все-таки делать, если нам нужно:

  1. использовать attachMovie с достаточно "тяжелыми" (большими по размеру) клипами;
  2. создать предзагрузчик?

Можно сделать "внешний" предзагрузчик. Идея состоит в следующем. Основной ролик создается таким образом, как будто предзагрузчик использовать не предполагается (всем нужным символам устанавливается галочка "Export in first frame"). Кроме того, создается отдельный ролик, в котором:

  1. размещается трехкадровый цикл предзагрузчика;
  2. основной ролик загружается с помощью loadMovie.

В основном ролике в первом же кадре проигрывание останавливается с помощью команды stop(), после того, как он полностью загрузится, его проигрывание запускает команда play() из ролика-загрузчика.
Объясним все на примере (рассматривается ролик-загрузчик, в основном ролике кроме команды stop() в первом кадре нет ничего специфического).
В первый кадр помещаем приблизительно такой код:

_root.createEmptyMovieClip("my_mc", 1);
// создаём пустой клип, в который будем загружать основной ролик;
my_mc.loadMovie("main.swf"); //загружаем основной ролик
        

Второй кадр оставляем пустым.
В третьем кадре пишем:

txt.text += my_mc.getBytesLoaded()/my_mc.getBytesTotal()+"\n";
// (или любой другой код, обновляющий проценты загрузки)
// если еще не все загрузили, ждем
if (my_mc.getBytesLoaded()/my_mc.getBytesTotal() < 1)
gotoAndPlay (2);
        

В четвертом кадре:

my_mc.play(); // запускаем проигрывание загруженного ролика
stop();       // останавливаем проигрывание:
        

Не забывайте про правила использования _level0 из загруженных с помощью loadMovie или loadMovieNum роликов (подробнее об этом см. раздел, посвященный загрузке роликов в этой лекции).
Еще раз напомним, если в основном ролике используется runtime sharing, вы не сможете учесть размеры runtime-shared компонентов заранее.

Управление процессом выполнения

Хорошо, мы обеспечили заблаговременную загрузку основного ролика до начала его проигрывания (с помощью остановки его в первом кадре и контролирования процента загрузки).
А что делать, если мы все-таки используем runtime-shared модули в основном ролике? Вы уже поверили нам на слово, что вы не сможете отследить проценты их загрузки, но хотя бы заставить их все загрузиться до начала основной анимации мы можем? Да. Как именно - см. пункт "Контролируемая загрузка клипов" из раздела "runtime sharing" лекции, посвященной командной разработке.
Здесь же хочется упомянуть о хорошем приеме - скрытии (_visible = false) _root до полного окончания загрузки. Сделать этоможно в разных местах, можно из внешнего предзагрузчика, а можно - из шаблона (см. пункт "Управление процессом" раздела "Шаблоны для разработки" из лекции, посвященной командной разработке).

Для чего еще можно использовать предзагрузчики

Мы рассмотрели основные аспекты использования предзагрузчиков, и вы уже видите, что их роль - не только показать заставку, пока грузится основной ролик.
Их задача более общая - управление процессом загрузки.
Рассмотрим еще одно важное применение предзагрузчиков - синхронизация асинхронных процессов - на примере загрузки ini-файлов.
Вы, наверное, обратили внимание, что пользоваться LoadVars не так уж удобно. Самое большое неудобство состоит в том, что нужно определять callback-обработчик, и только в нем становятся доступны нужные настройки. Иными словами, вы не можете использовать настройки в удобном для вас месте, потому что вы не знаете, загрузились они уже или нет. Поэтому вам приходится "чесать правой рукой левое ухо". Например, вместо того, чтобы в конструкторе компонента использовать уже готовый параметр "язык", вам приходится заводить центральный объект, который разошлет всем компонентам события "изменился язык, перерисуйтесь, пожалуйста", а это, согласитесь, намного более сложный механизм, и не вполне адекватный, ведь скорее всего вам никогда не понадобится по несколько раз менять язык флэш-ролика.
Вместо этого вы могли бы сделать предзагрузчик, который загрузит все необходимые ini-файлы и вообще сделает все подобные асинхронные вещи, после чего он загрузит основной ролик, который уже будет "на всем готовеньком" (общение основного ролика с предзагрузчиком, пожалуй, лучше организовать через какой-нибудь объект, размещенный в _global, чем использовать _level0).

Передача параметров флэш-ролику из HTML

Рассмотрим еще один способ настройки флэш-ролика извне.
Этот способ немного похож на использование ini-файлов, но имеет совершенно другую природу.
Заключается он в использовании возможности передачи параметров встраиваемому объекту (plugin или ActiveX) из HTML-кода, создающего plugin- или ActiveX-объект (затем эти переменные будут доступны как переменные _level0).
Существует два синтаксиса передачи параметров флэш-ролику:

  • Запись параметров в url-формате (param=value&param=value) в параметре movie тегов <OBJECT> и <EMBED> через '?'. Например:
<param name=movie value ="myflash.swf?par1=value1&par2=value2">.
     

У этого способа есть один недостаток: он не работает с версией флэш-плеера 6.0.47.0.

  • Запись параметров в url-формате в отдельном специальном параметре FlashVars теги <OBJECT> и <EMBED>. Например:
<param name=movie value="myflash.swf">
<param name= FlashVars value="par1=value&par2=value2">
     

Этот способ не работает в версиях плейера раньше 6.0.
Рекомендуем использовать оба способа одновременно, если ваши флэш-ролики предполагается проигрывать на флэш-плеерах версий 5.0 и более старых. В остальных случаях используйте второй способ.
Отметим, что передачей параметров флэш-ролику из HTML зачастую пользоваться удобнее, чем ini-файлами, потому что не возникает проблем с асинхронностью: сразу после загрузки ролика все параметры доступны как переменные _level0.

Взаимодействие с браузером

В предыдущем параграфе мы рассмотрели самый простой вид взаимодействия браузера и флэш-плеера: передачу параметров из первого последнему.
Но это далеко не единственный тип взаимодействия, который можно использовать. Вы можете управлять роликом (например, запускать и останавливать ролик, получать и устанавливать значения переменных ролика) из JavaScript (или VBScript), и наоборот - вызывать функции JavaScript или VBScript из флэш-ролика.
Рассмотрим данные механизмы более подробно.

Управление роликом из JavaScript

Синтаксис JavaScript-команды, обращающейся к ролику, таков:

movie.methodName (parameters);
        

Здесь movie - ссылка на plugin- или ActiveX-объект флэш-плеера, то есть window.document.<имя ролика>, где <имя ролика> - это параметр ID для тега OBJECT и параметр NAME для тега EMBED, methodName - имя одного из методов plugin- или ActiveX-объекта флэш-плеера (далее будем называть их флэш-методами, о них см. далее).
Перечислим самые полезные флэш-методы, полный их перечень можно посмотреть, например, здесь: http://www.macromedia.com/support/flash/publishexport/scriptingwithflash/scriptingwithflash_03.html.
Получение значения переменной: GetVariable(varName)
Пример:

var radioButtonValue =
movie.GetVariable("/Form/RadioButton:Value");
        

Установка значений переменной:

SetVariable(variableName, value)
        

Пример:

movie.SetVariable("textField.variableName, text", "someText");
        

Запуск проигрывания: Play()
Пример:

movie.Play();
        

Остановка проигрывания: StopPlay()
Пример:

movie.Stop();
        

Перевод ролика на нужный кадр: GotoFrame(frameNumber)
Пример:

movie.GotoFrame (_root, 5);
        

Выполнение кода из кадра клипа. Можно использовать для вызова метода, если поместить вызов метода в этот кадр.

TCallFrame(object, frameNumber)
        

Пример:

movie.TCallFrame("myMovieClip", 10);
        

Вызов методов JavaScript и VBScript из флэш-ролика

Рассмотрим теперь, как можно добиться обратного эффекта - вызвать функцию JavaScript или VBScript из флэш-ролика.
Для всех внешних вызовов из флэш-ролика предназначен метод fscommand (другие его применения мы рассмотрим в следующем параграфе).
Синтаксис инструкции fscommand:

fscommand (command, arguments);
        

Если флэш-ролик выполняется в браузере, то этот метод приводит к вызову одной из функций: VBScript-функции <movieName>_FSCommand (эта функция, например, вызывается в Internet Explorer для Windows) или JavaScript-функции <movieName>_DoFSCommand (эта функция, например, вызывается в Netscape). Так все хитро устроено внутри браузеров, а точнее, внутри подключаемых (plug-in) модулей или объектов ActiveX, которые выполняют функции флэш-плееров в браузерах - именно плеер вызывает у браузера одну из вышеуказанных функций.
Какая бы из этих двух функций ни была вызвана, ей в качестве первого аргумента передается сommand, а в качестве второго - arguments (это два параметра, указаннные при вызове fscommand).
Давайте разберемся, как этим пользоваться. Скорее всего, вы хотите добиться одинакового поведения во всех браузерах. Тогда нужно сделать, чтобы в любом случае вызывалась одна функция. Для этого просто продублируем входной интерфейс. Вот как, например, это можно сделать:

<SCRIPT Language=JavaScript>
function mymovie_DoFSCommand (cmd, args) {
   // эта функция вызывается в результате выполнения fscommand 
   // в Netscape
   //...
}
</SCRIPT>
<SCRIPT Language=VBScript>
Sub mymovie_FSCommand (ByVal cmd, ByVal args) 
   call mymovie_DoFSCommand (cmd, args);
End Sub
</SCRIPT>
        

Есть и другой вариант, не связанный с помещением нужного вам JavaScript или VBScript-кода в html-документ. Вы можете просто воспользоваться инструкцией getURL, а в качестве адреса передать строчку наподобие "javascript: alert('Text of Alert')". Собственно говоря, после префикса javascript: может идти довольно большое количество операторов (разделенных двоеточиями, разумеется). Правда, отладка ролика, содержащего подобный вызов во встроенном редакторе будет неудобна - все время будет запускаться браузер для того, чтобы выполнить заданную команду. Использование fscommand не имеет такого побочного эффекта.
Следует заметить, что описанные выше взаимодействия флэш-ролика с браузером через JavaScript работают не на всех платформах (в частности, они не работают в Internet Explorer под MacOS, а также в Mozilla). Это может быть очень неудобно, например, когда нужно организовать взаимодействие двух флэш-роликов, флэш-роликов и апплетов и пр. В таких случаях можно рассматривать альтернативные варианты:

  • LocalConnection (если речь идет о взаимодействии двух флэш-роликов)
  • Организация коммуникаций через веб-сервер;
  • Перезагрузка флэш-роликов в отдельных фреймах из JavaScript с передачей им нужных параметров (теги <OBJECT> и <EMBED> полностью генерируется с помощью JavaScript;

Первый и второй варианты мы отчасти рассмотрим далее в этой лекции.

Другие применения fscommand

С помощью fscommand можно не только вызывать методы JavaScript, как мы уже говорили. Например, с ее помощью можно командовать консольным плеером. То же самое справедливо для ролика, выполняемого как projector (опубликованного в exe-файл, внутрь которого встроен плеер).
Вот как это делается:

fscommand ("showmenu", false);
        

В результате пропадет линейка меню плеера, а контекстное меню будет сильно уменьшено.
Можно также запустить какое-либо приложение Windows.

fscommand ("exec", "calc.exe");
        

Как нетрудно догадаться, эта команда запустит калькулятор Windows. Впрочем, настройки безопасности системы могут не позволить такого сделать (не говоря уже о том, что из браузера ничего подобного устроить нельзя).
Наконец, если вы работаете не только с Macromedia Flash MX, но и с Macromedia Director (в фильмы которого можно встраивать флэш-ролики), то fscommand может применяться для того, чтобы отдавать команды Shockwave-плееру (проигрывающему фильмы Macromedia Director) на языке Lingo. За подробностями вам следует обратиться к документации по системе Macromedia Director.

Local Connection

Если нужно организовать взаимодействие между несколькими роликами на одном компьютере, можно воспользоваться LocalConnection. Этот класс позволяет организовывать коммуникации между двумя флэш-роликами, которые запущены в разных браузерах, или даже в разных типах плееров (например, один в браузере - а другой интегрированный во флэш-среду).

Как настроить ролик-приемник

Во-первых, нужно создать объект LocalConnection:

incoming_lc = new LocalConnection();
        

Во-вторых, нужно открыть соединение со специальным центральным объектом:

incoming_lc.connect("lc_name");
// lc_name будет использоваться при передаче данных
        

В-третьих, нужно определить метод-обработчик:

incoming_lc.methodToExecute = function (param) {
   trace (param);
};
        

Как настроить ролик-передатчик

Нужно создать объект LocalConnection:

outgoing_lc = new LocalConnecton();
        

Теперь можно отправлять сообщения первому ролику, указав имя центрального объекта, имя метода обработчика и объект, который нужно передать:

outgoing_lc.send("lc_name", "methodToExecute", "someText");
        

В роли текстовой строки "someText" здесь может выступать любой объект.
Кстати, только что рассмотренный пример представляет собой внешнюю отладочную консоль, которую сделать намного проще, чем встроенную во флэш-ролик (см. раздел "Отладка" из этой лекции).

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

Shared Objects
Иногда возникает необходимость использовать во Флэш что-то вроде cookies. Допустим, у вас есть какой-то флэш-сервис на сайте, например, игра, в которой пользователь может ввести свое имя, и вы хотели бы, чтобы это имя сохранилось и отображалось в игре при каждом следующем заходе пользователя на сайт.
Для решения такой задачи во Flash MX есть специальная технология - Shared Objects. Она работает примерно так же, как cookie: флэш-ролику предоставляется объект, который затем сохраняется на локальном диске, и который можно запросить при следующем запуске флэш-ролика.
Рассмотрим использование Shared Objects на примере флэш-ролика, имеющего текстовое поле, содержимое которого можно редактировать; мы сделаем так, чтобы это содержимое автоматически сохранялось между запусками ролика.
Считаем, что у нас на сцену помещено текстовое поле ввода, которое называется 'txt'.
Поместим в первый кадр такой код:
txt.onChanged = function () {
//обработчик изменения текста в текстовом поле
var obj = SharedObject.getLocal("savedObject");
// получаем хранимый объект с именем "savedObject"
obj.data.text = txt.text;
// сохраняем в его поле data нужные нам свойства (это
// специальное поле, и только оно сохраняется на диске)
obj.flush(); //записываем объект на диск
}
obj = SharedObject.getLocal("savedObject");
// при каждой загрузке ролика получаем объект, и если в нем
// сохранен текст, записываем его в текстовое поле.
if (obj.data.text != undefined) {
txt.text = obj.data.text;
}

Запустив эту программу увидим, что содержимое текстового поля действительно сохраняется. Обратите внимание, что метод SharedObject.getLocal в одном случае создал нам новый сохраняемый объект, а в другом (когда объект с запрошенным именем нашелся в хранилище) - выдал уже имеющийся.

Изменение текущей директории (атрибут BASE)
В некоторых случаях возникает необходимость положить html-файлы, загружающие флэш-ролик, в каталог, отличный от каталога, в котором лежат *.swf-файлы.
Это может привести к проблеме, связанной с тем, что флэш-ролик в таком случае будет считать "текущей директорией", точнее, точкой отсчета путей, именно каталог с html-файлом (а это, видимо, не то, что вы хотели получить). Результат - нужные файлы (например, модули runtime sharing, ini-файлы и пр.) не будут найдены.
Для таких целей (изменение точки отсчета путей во флэш-ролике) специально предназначен атрибут BASE у тегов <OBJECT> и <EMBED>. Его значением может быть:

  • путь (относительный или абсолютный), который будет считаться точкой отсчета путей во флэш-ролике;
  • специальное значение '.'.

Если в качестве значения атрибута BASE указать ".", то точкой отсчета путей считается каталог, в котором лежит *.swf-файл с флэш-роликом. (Однако будьте осторожны, в некоторых случаях, точно определить которые довольно затруднительно, эта настройка действует не сразу - не с первого кадра. В таких случаях можно добавить дополнительную начальную сцену, чтобы "переждать неприятности".)
Скорее всего, вы хотите, чтобы точкой отсчета путей был каталог, в котором лежит *.swf-файл с флэш-роликом, а это можно сделать как первым, так и вторым способом. Какой из них использовать? Казалось бы, все равно. Но не совсем.
Если вы не используете runtime sharing, можете смело применять любой и пропускать остаток параграфа, но если используете - придется вникнуть в то, что написано дальше.
Прочитайте про проблему зацикленной загрузки runtime-shared символов из пункта "Возможные проблемы" раздела "Runtime sharing" из лекции, посвященной командной работе. Ключевым моментом здесь является то, что путь, указанный в BASE, влияет на некий эталонный путь, сравниваемый с путями, указанными в параметре URL области linkage свойств символа. Еще раз, если они не совпадут до символа (это сравнение происходит где-то в недрах флэш-плеера), то возникнет проблема зацикленной загрузки и утечки памяти.
Что делать? В общем случае, если у вас возникает указанная проблема, попробуйте понять, чему равен каждый из путей и как сделать, чтобы они совпали. Но приведем все же пример работающей конфигурации (которой мы пользовались в одном из проектов):

  1. используйте в параметре URL области linkage просто имя *.swf-файла.
  2. для всех платформ кроме "IE+MacOS+работа с локального диска" установите BASE = ".".
  3. для платформы "IE+MacOS+работа с локального диска" установите BASE="file:///<полный путь к *.swf-файлу>.

Динамическую генерацию BASE удобнее всего сделать путем генерации тегов <OBJECT> и <EMBED> с помощью JavaScript.

Загрузка звуков

Во Flash MX есть объект Sound, позволяющий проигрывать звуки, которые либо импортированы в библиотеку ролика, либо загружены из MP3-файла.
Много времени этому объекту мы уделять здесь не будем, но рассмотрим особенности, касающиеся загрузки внешних MP3-файлов через Интернет.
Объект Sound поддерживает два сценария работы: для потоковых звуков (streaming) и звуков-событий (event).

Потоковые звуки

Потоковые звуки - это предположительно длинные звуки, например, музыкальное сопровождение, которые играют по мере загрузки. Вот как можно пользоваться потоковыми звуками:

mySound = new Sound();
mySound.loadSound("song1.mp3", true);
//true - означает, что звук потоковый.
        

Звуки-события

Звуки-события - это предположительно короткие звуки, которые должны быть проиграны за один раз (без пауз).
Пример использования звука-события:

mySound = new Sound();
mySound.onLoad = function () {
   this.start();
}
mySound.loadSound ("event1.mp3", false);
        

У объекта Sound также определены методы getBytesLoaded() и getBytesTotal(), с помощью которых можно точнее отслеживать, какая часть звука уже загружена, что можно использовать для реализации предзагрузчиков.

Работа с XML

Для чего можно использовать XML во Флэш МХ? Например, для:

  • параметризации флэш-роликов (описание состояния флэш-ролика);
  • взаимодействия с сервером.

Во Flash MX есть довольно хорошее DOM-ориентированное API, предоставляющее доступ к структуре дерева разобранного флэш-плеером XML.
Всю необходимую функциональность предоставляет объект XML, про который можно почитать в разделе "Objects / Client/Server" Flash Reference. Мы же подробно останавливаться на описании этого объекта здесь не будем, рассмотрим только самые нужные операции, а также обсудим моменты, характерные для работы с объектом XML в Интернет.

Навигация по дереву XML

Обсудим самые нужные операции на примере.
Пусть у нас есть такой XML:

<root>
<person age='25'>Kate</person>
<person age='24'>John</person>
</root>
        

Напишем фрагмент кода, позволяющий вывести эту информацию в табличном виде.

xmlObj = new XML (
"<root><person age='25'>Kate</person><person age = '24'>John</person></root>"
); //создали XML-объект 
xmlObj.ignoreWhite = true; 
// командуем игнорировать пробелы (не считать их узлами дерева)
var rootElement = xmlObj.firstChild; 
// ссылка на корневой элемент
for (
var person = rootElement.firstChild; person != null; 
person = person.nextSibling
) {
  trace (person.firstChild.nodeValue + ": " 
+ person.attributes.age);
}
        

Давайте обсудим цикл более подробно.
В начале переменная person ссылается на первый дочерний элемент в <root>, коим является первый тег person. Текст "Kate" является вложенным в него элементом, поэтому обращение к нему требует еще одного firstChild. Этот элемент (Kate) - элемент-"примитив" (не содержит вложенных элементов, поэтому у него определено свойство nodeValue, равное "Kate". К атрибутам элемента person мы обращаемся через его свойство attributes, являющееся объектом-"хэш-таблицей" атрибутов. Прежде чем перейти к очередной итерации цикла, мы присваиваем переменной цикла person свойство nextSibling, указывающее на следующий элемент, лежащий на одном уровне с person. Так мы переходим к обработке следующего человека.

Получение XML с сервера и отправка его на сервер

В предыдущем примере мы создали объект XML из текстовой строки. В реальных условиях иногда все не так просто, например, может понадобиться загрузить XML с веб-сервера или, наоборот, отослать его на веб-сервер.
Рассмотрим пример загрузки XML c веб-сервера.

var xmlObj = new XML():
xmlObj.onLoad = function () {         //callback-обработчик
   //...здесь уже можно обходить дерево XML и читать данные
}
xmlObj.load(http://www.myserver1.com/cgi-bin/getxml.cgi);
        

Объект также позволяет отправлять XML на сервер (метод send), одновременно отправлять и загружать ответ (метод sendAndLoad). Для контроля над процессом загрузки можно использовать методы getBytesLoaded() и getBytesTotal(). Эти методы полностью аналогичны одноименным методам из класса LoadVars за тем естественным исключением, что отсутствует аргумент, задающий тип запроса. XML всегда приходит на сервер с запросом POST (за исключением того случая, когда XML пуст, тогда, как обычно, применяется метод GET). Все прочие особенности работы методов те же, и даже ошибки в документации совпадают.

Пара слов о специальных серверных решениях
К настоящему моменту мы рассмотрели несколько механизмов, с помощью которых флэш-ролик может взаимодействовать с веб-сервером, например LoadVars, XML, Sound.
Такие инструменты, как LoadVars, XML, getURL позволяют решить много задач, связанных с серверным взаимодействием через HTTP, а с помощью XMLSocket можно взаимодействовать с сервером напрямую через TCP/IP.
В этом разделе мы коротко рассмотрим последний из названных способов взаимодействия, а также некоторые другие технологии.
XMLSocket
Итак, мы уже сказали, что во Flash MX существует механизм для организации сетевых взаимодействий на уровне TCP/IP. И что для этого предназначен класс XMLSocket. Он очень похож на класс LoadVars по своей структуре, так как тоже служит для асинхронной передачи данных (в XML-формате).
Рассмотрим один из стандартных сценариев использования этого класса. Создаем XML-объект для пересылки.
var myXML = new XML();
var myLogin = myXML.createElement("login");
myLogin.attributes.username = usernameTextField;
myLogin.attributes.password = passwordTextField;
myXML.appendChild(myLogin);
myXMLSocket = new XMLSocket();
// создаем сокет (допустимы только клиентские)
// открываем соединение с сервером
// здесь "myserver" - имя сервера, "1457" - номер TCP-порта
myXMLSocket.connect ("myserver", "1457");
myXMLSocket.send(myXML); //отправляем данные
myXMLSocket.close(); //закрываем соединение

Класс позволяет определить несколько обработчиков для реакции на стандартные события:
cnClose() - соединение закрыто сервером
onConnect (success) - запрос connect() выполнен. Если параметр success равен true, то соединение успешно открыто, если false - соединение установить не удалось.
onData (data) - с сервера пришел нуль-терминированный ответ data (завершающий нуль-символ не включается в параметр data). По умолчанию реализация onData() вызывает обработчик onXML(), как если она бы выглядела вот так:
XMLSocket.prototype.onData = function (src) {
this.onXML(new XML(src));
}

Эту реализацию можно подменить, если не нужно заниматься синтаксическим разбором XML, а достаточно строки, возвращенной сервером.
onXML(object) - с сервера пришел нуль-терминированный ответ. В параметре object - результат разбора строки ответа, которая может иметь вид:
<MESSAGE USER="John" TEXT="Hello, my name is John!" />

Тогда обработчик можно написать так:
function myOnXML(doc) {
var e = doc.firstChild;
if (e != null && e.nodeName == "MESSAGE") {
displayMessage(e.attributes.user, e.attributes.text);
}
}
myXMLSocket.onXML = myOnXML;

Flash Remoting
При написании флэш-сайтов, отображающих реальные данные, очень часто повторяются одинаковые операции: соединение с сервером, отправка запроса, получение и интерпретация ответа.
Одна из технологий, разработанных Macromedia и призванных упростить этот процесс - это Flash Remoting MX.
Flash Remoting представляет собой двухкомпонентную надстройку над интерфейсом взаимодействия клиента и сервера.
На клиенте она реализуется в виде API NetServices, последние устанавливаются как специальный набор компонентов, которым пользуется флэш-приложение для обращения к бизнес-сервисам, а серверная часть реализована отдельно для разных провайдеров бизнес-логики: J2EE, Microsoft ASP.NET, SOAP Web Services, ColdFusion MX.
Например, для J2EE - это сервлет, для ASP.NET - сборка и т. д.
Обмен данными производится с помощью бинарных сообщений AMF (ActionScript Message Format), типы данных автоматически конвертируются из типов ActionScript в типы данных сервера приложения и назад.
Использование Flash Remoting-сервисов на клиенте очень похоже на использование веб-сервисов, но оно всегда асинхронное: для получения ответов пишутся ActionScript-обработчики специальной сигнатуры.
Сейчас мы приведем слегка укороченный вариант примера, приведенного на сайте Macromedia (вот в этом документе http://livedocs.macromedia.com/flashremoting/mx/Using_Flash_Remoting_MX/UseActionScript7.htm#1192607 ; чуть ниже помещена ссылка на полную подборку документации, к которой принадлежит сей документ). Итак, вот обещанный пример:
function getTemperature_Result(temperature)
{ temperatureIndicator.text = temperature; }
function getForecast_Result(forecast)
{ forecastIndicator.text = forecast; }
weatherService.getTemperature("New York");
weatherService.getForecast("Chicago");

Также существует специальная поддержка для обработки серверных исключений и отладки (NetConnection Debugger).
Клиентские компоненты FlashRemoting для Flash MX можно бесплатно загрузить с сайта Macromedia (в отличие от серверных надстроек, которые нужно покупать).
Какие еще бывают серверные решения
Для полноты картины упомянем еще пару решений от Macromedia. В свое время достаточно известен был Macromedia Generator, который устанавливался на сервере и генерировал swf-файлы по специальным шаблонам (шаблоны эти можно было приготовить при помощи Macromedia Flash). В настоящее время эта технология уже устарела (самая свежая документация, которую нам удалось отыскать на сайте Macromedia, касалась совместной работы Generator и Flash 5).
Зато появилась еще одна многообещающая технология под названием Macromedia Flash Communication Server MX. Чтобы использовать ее, вам нужно приобрести у Macromedia соответствующий продукт (впрочем, пробная версия даже после истечения периода опробования все еще оставляет возможность создавать до пяти одновременных соединений, что вполне достаточно для целей разработки). Итак, вы устанавливаете на своем сервере Flash Communication Server. Для обмена данными с сервером в клиентском ролике сначала создается объект NetConnection, с помощью которого открывается соединение. А затем происходит обмен данными с помощью уже знакомого нам класса SharedObject (только используется не метод getLocal, а метод getRemote). В принципе, все эти механизмы рассчитаны скорее на Flash MX 2004, поскольку во Flash MX класс NetConnection еще не документирован (хотя и существует). Вы можете почитать подробнее о работе с Communication Server, скажем, переводную статью на, она расположена по адресу

Отладка
Основная информация, касающаяся отладки во Flash MX, уже была приведена ранее в лекции "Базовые понятия ActionScript". Но когда вы выкладываете флэш-проект в Интернет, у вас появляются специфические проблемы и вам становятся нужны специфические средства отладки.
Например:

  • Если вы используете внешний предзагрузчик, вам уже будет мало обычного режима отладки, позволяющего отлаживать один флэш-ролик;
  • Вам понадобится имитация условий Интернет, то есть ограничение пропускной способности канала;
  • Некоторые проблемы проявляются только на части аппратно-программных платформ, под которыми отладчик может быть вам недоступен.

В этом разделе мы и рассмотрим специфику отладки флэш-проектов в Интернет.
Отладочная консоль
Одним из основных отладочных инструментов всегда является отладочная консоль, которая, к сожалению, во Флэш МХ доступна только в среде разработки. Если же вы хотите запустить проект в реальных условиях, вы не сможете увидеть отладочной информации, выводимой с помощью trace.
Для того чтобы решить эту проблему, можно сделать специальную отладочную консоль, в которую выводить информацию специальными методами.
Как сделать такую консоль? Это обычный клип, содержащий большое текстовое поле с полосами прокрутки, который скрывается и показывается по нажатию на специальную клавишу, например F12 или F2 (мы в одном из проектов сделали консоль, реагирующую на любую из этих клавиш, потому что F2 в среде Флэш МХ под Windows открывает стандартную консоль, а F12 под управлением MacOS открывает CD-ROM). Кроме того, нужно еще написать общедоступные функции для вывода отладочной информации, которые взаимодействуют с клипом консоли.
Примерно так может выглядеть код класса-клипа консоли:
#initclip
function Console () {
// здесь, использую Stage.width и Stage.height,
// устанавливаем размеры элементов консоли
this._visible = false; //прячем консоль
Key.addListener(this); //включаем реакцию на клавиатуру
}
Console.prototype = new MovieClip ();
Console.prototype.onKeyDown = function () {
//Используем коды клавиш F2 && F12
if ((Key.getCode() == 123 || Key.getCode() == 113) && _global.DEBUG > 0) {
this._visible = !this._visible;
// показываем или прячем обновляем содержимое консоли
if (this._visible) this.edit.text = _global._CONSOLE_LOG;
}
}
Object.registerClass("Console", Console);
#endinitclip

А вот так, например, может выглядеть отладочная функция.

_global.infoMsg = function (message) {
if (_global.DEBUG > 1) {
trace (message);
_global._CONSOLE_LOG += message + "\n";
}
}

Примечание. Упрощенный вариант отладочной консоли можно сделать с помощью LocalConnection, который был описан выше в этой лекции (отладочная информация выводится в другом флэш-ролике: например, с помощью trace, если на данной платформе есть среда Flash MX, или в текстовое поле, если нет). В любом случае самой кропотливой части (выравнивание элементов консоли, реакция на клавиатуру) можно в таком упрощенном варианте избежать.

Удаленная отладка
Удаленная отладка, которая есть во Flash MX, - исключительно полезный инструмент для отладки "в боевых условиях". С его помощью вы можете запустить флэш-ролик в нужной конфигурации (используя любые html-шаблоны, предзагрузчики и т. п.) на нужной платформе с нужного веб-сервера, после чего подключиться к нему отладчиком.
Делается это так. Во-первых, вам понадобится специальная, отладочная версия флэш-плеера. Ее можно скачать с Macromedia, об этом читайте, например, здесь:
Если у вас установлена отладочная версия флэш-плеера, в контекстном меню флэш-роликов появляется пункт debug (он может быть disabled, если при компиляции ролика отладка была запрещена). Отладочную версию, разумеется, нужно устанавливать на компьютер, на котором вас интересует работа флэш-ролика.
Во-вторых, нужно разрешить отладку конкретного флэш-ролика. Для этого зайдите в File / Publish Settings / Flash и установите галочку Debugging Permitted.
В-третьих, нужно разрешить удаленную отладку на том компьютере, на котором у вас установлена среда разработки Flash МХ. Откройте Window / Debugger (Shift-F4) и в контекстном меню (которое отображается при нажатии на кнопку в правом верхнем углу) включите галочку Enable Remote Debugging.
Выполнив все эти действия, вы можете в любой момент выбрать пункт Debug из контекстного меню флэш-плеера. Во всплывающем окошке нужно ввести адрес машины, на которой запущена среда Flash МХ (если в среде указано, что удаленная отладка разрешена, она слушает определенный порт). Если вы работаете в локальной сети, скорее всего, будет достаточно просто имени машины. После этого можно отлаживать ролик удаленно, при этом работают все средства отладки, такие, как точки останова, просмотр исходного кода и т. п. Разумеется, тот же прием работает и тогда, когда плеер и среда запущены на одной и той же машине.
Здесь есть одна тонкость. Когда вы компилируете флэш-ролик с установленной галочкой Debugging Permitted, создается специальный *.swd- файл с отладочной информацией, который используется в процессе отладки. Этот файл должен лежать в том же каталоге, где и *.swf-файл. Если этот файл доступен, отладочный флэш-плеер сразу при загрузке флэш-ролика предложит подсоединиться к компьютеру с установленной средой разработки Flash МХ. Если же *.swd-файла нет, то нужно будет самому выбрать пункт debug из контекстного меню, а кроме того, многие функции отладки, в частности, точки останова и исходный код, будут недоступны.
Тестирование на канале малой пропускной способности
Как мы уже отмечали ранее, некоторые проблемы (например, рассинхронизация runtime shared клипов) проявляется только на узком канале. Кроме того, только в таких условиях имеет смысл тестировать, например, предзагрузчики. Далее мы рассмотрим два различных метода тестирования флэш-проектов при малой пропускной способности канала.
Bandwidth profiler
Bandwidth profiler - встроенное во Flash MX средство, позволяющее имитировать узкую пропускную способность канала. Это средство идеально подходит для тестирования длинных анимационных роликов, содержащих большое количество кадров, с предзагрузчиками, размещенными внутри того же флэш-ролика.
Запустите ваш флэш-ролик из-под встроенного во флэш-среду проигрывателя (Ctrl-Enter) и выберите Bandwidth profiler в меню View (Ctrl-B). Выберите желаемую пропускную способность канала в меню Debug, после чего выберите Show Streaming в меню View (Ctrl-Enter). Теперь в центральной области экрана можете наблюдать, как работает ваш флэш-ролик при выбранной пропускной способности канала, а в верхней части отображается диаграмма загрузки кадров в одном из двух возможных режимов: Frame by Frame Graph (Ctrl-F) или Streaming Graph (Ctrl-G).
В режиме Frame by Frame Graph каждому кадру на линейке соответствует один столбик на диаграмме, размеру кадра ставится в соответствие высота столбика. Если высота столбика превышает красную линию (пропускная способность канала, деленная на частоту кадров), то данный кадр является узким местом (в принципе, можно постараться использовать эту информацию, чтобы максимально "выровнять" кадры и избежать узких мест). Впрочем, при использовании предзагрузчиков данная проблема не актуальна.
В режиме Streaming Graph каждому из столбиков соответствует как бы квант загрузочного времени, и становится виден весь процесс загрузки: если флэш-плеер загрузил маленький кадр, он сразу же грузит следующий в буфер, даже если его время еще не пришло, за счет этого у него появляется запас, и он может успеть загрузить кадры, которые занимают больше одного столбика. Там, где столбики поднимаются выше красной линии, флэш-плеер не успеет загрузить нужный кадр, и образуется узкое место.
Тестирование с помощью специальных web-серверов
Как вы уже заметили, Bandwidth profiler особенно полезен, когда во флэш-ролике много кадров.
А если у вас все наоборот - весь флэш-ролик состоит из одного кадра, то никакой особой пользы вы из bandwidth-профайлера не извлечете. А если у вас еще и внешний предзагрузчик или html-шаблон, то и вообще запустить проект под этим профайлером не удастся.
Для этого можно воспользоваться имитацией условий Интернет на более низком уровне, например, на уровне веб-сервера. Многие веб-сервера позволяют ограничивать пропускную способность канала. Одним из таких является легкий бесплатный сервер Xitami от Imatix corporation, который можно скачать с. После его установки зайдите на страницу администрирования () и укажите нужную пропускную способность канала (pipe throttle). Перезапустите веб-сервер.
Обратите внимание: после каждого захода на веб-страницу с тестируемым флэш-роликом вам придется стирать кэш браузера. В Internet Explorer это делается нажатием на кнопку Delete Files области Temporary Internet Files закладки General меню Tools / Internet Options.

Возможные проблемы
В этом разделе коротко обсудим ряд моментов, которые могут вызвать неработоспособность флэш-проекта при выкладывании его в Интернет (часть из них уже была рассмотрена детальнее в других лекциях).
Веб-серверы на Unix/Linux и Case-sensitivity
Как вы знаете, файловые системы Unix и Linux чувствительны к регистру (в отличие от Windows). Это касается также и HTTP-запросов к веб-серверам, работающим под управлением Unix/Linux. Поэтому у вас может возникнуть такая ситуация: пока вы тестируете флэш-проект с Windows-веб-сервера, все работает прекрасно, а как только выкладываете на Unix/Linux - все перестает работать.
Вам придется внимательно пересмотреть все пути, которые используются внутри флэш-ролика, например, пути runtime sharing, параметры URL LoadVars, XML и подобных средств, и заменить большие буквы на маленькие (или наоборот). Это можно автоматизировать с помощью, например, UltraEdit, который позволяет заменить одну строчку на другую сразу во многих файлах (имеются в виду *.fla-файлы). Редактировать файлы придется, разумеется, в бинарном режиме (впрочем, UltraEdit сам разберется).
Иногда во *.fla-файлах остаются старые, не используемые более пути, и тогда бывает сложно найти, что требуется заменить. В таких случаях можно просмотреть *.swf-файлы (предварительно нужно отключить ихсжатие: Publish Settings / Flash / Compress Movie), в которые попадают только действительно используемые пути.
MacOS и механизмы типа LoadVars
Допустим, вы используете LoadVars для работы с ini-файлами. Под Windows, если в запрашиваемом файле ничего нет или нет самого файла, все работает прекрасно, но под MacOS все не так замечательно: при выполнении хотя бы одного из двух условий флэш-плеер будет очень долго ожидать, в результате время загрузки увеличится в несколько раз.
Поэтому сделайте пустые ini-файлы (или другие соответствующие файлы, которые вы используете) и запишите в них по одной строчке, например: __somevar = somevalue.
runtime-загрузчики
Если вы используете runtime sharing, и ваш проект перестает работать, как только вы его выкладываете на веб-сервер, возможно, дело в том, что вы не используете runtime-загрузчики. Детальнее об этом см. в лекции "Методика организации командной работы над Flash-проектом" в разделе "Runtime sharing".
Контролируемая загрузка клипов
Опять же, если вы используете runtime sharing, и ваш проект перестает работать, как только вы его выкладываете в Интернет, возможно, у вас "рассинхронизировались" *.swf-модули в результате увеличения времени загрузки. Детальнее об этом см. в лекции "Методика организации командной работы над Flash-проектом" в разделе "Runtime sharing".
Кстати, механизм контролируемой загрузки может стать, в свою очередь, причиной неработоспособности проекта (если модулей загрузилось меньше, чем ожидалось, флэш-ролик будет находиться в вечном ожидании и никогда не загрузится).

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика