Статьи

Построить GPS-спидометр: вход в AIR для Android

Почти каждый смартфон в наши дни имеет возможности GPS, но приложения, использующие это, не обязательно должны быть скучными старыми картами. Это руководство познакомит вас с Adobe AIR для Android и проведет вас через разработку приложения спидометра ActionScript 3.0, которое будет работать на устройствах Android 2.2.

Посмотрите вторую часть этого руководства. Постройте GPS-спидометр: пользовательский интерфейс и польский на нашем родственном сайте Activetuts +!

Те, кто интересуется платформой, но еще не имеет устройства Android, могут следовать этому руководству и протестировать его во Flash Professional.


Adobe AIR для Android создает множество интересных возможностей для разработчиков Flash, желающих перейти в мобильное пространство.

Этот учебник познакомит вас с тонкими различиями при применении ваших навыков ActionScript для мобильных устройств. Он проведет вас через шаги, необходимые для написания, развертывания и тестирования полнофункционального приложения на вашем телефоне Android.

Особое внимание будет уделено классам геолокации и файловой системы, специфичным для AIR SDK.

Не беспокойтесь, если у вас нет телефона с Android 2.2. Вы по-прежнему сможете создавать и тестировать ActionScript в Flash CS5.


Прежде чем вы сможете начать разработку, вам необходимо скачать и установить следующие компоненты:

  1. Flash Professional CS5 (подойдет 30-дневная пробная версия)
  2. Среда выполнения Adobe AIR для Android 2.2
  3. Расширение Adobe Flash Professional CS5 для AIR 2.5
  4. Драйверы устройств USB (только для Windows)
  5. Adobe AIR 2.5.1 SDK

Если у вас еще нет Flash CS5, вы можете загрузить 30-дневную пробную версию с Adobe .

Если вы планируете развертывать и тестировать на реальном телефоне, вам нужно установить бесплатную среду выполнения Adobe AIR с Android Market (просто найдите Adobe AIR в приложении Market).

Я использовал Google Nexus One для этого урока, но AIR будет работать на устройствах Android, которые отвечают следующим системным требованиям:

  • Операционная система Android 2.2
  • ARMv7-A процессор с векторным FPU
  • OpenGL ES 2
  • Аппаратные декодеры H.264 и AAC
  • 256 МБ ОЗУ

Если AIR for Android не поддерживается для вашего телефона Android, вы все равно можете следовать этому руководству и протестировать его во Flash CS5.

Вы можете скачать расширение для AIR 2.5 от Adobe Labs . Инструкции по установке расширения можно найти здесь . Если вы используете Windows, вам также нужно будет выполнить шаги, описывающие, как установить драйверы USB-устройств, которые позволяют устройству Android взаимодействовать с Android SDK.

Наконец, загрузите и установите последнюю версию Adobe AIR SDK .

Хорошо, мы прочитали, чтобы начать кодирование.


Я предоставил FLA, содержащий обложки, необходимые для этого урока. Мы будем работать с этим FLA, но прежде чем мы это сделаем, давайте сначала ознакомимся с шагами, необходимыми для создания FLA, предназначенного для AIR for Android. В конце концов, вам нужно будет сделать это для любых ваших будущих проектов.

Я использую Windows 7 для этого урока, но при необходимости я предоставил инструкции для тех, кто использует Windows Vista, Windows XP и Mac OS X.

Запустите Flash CS5 и выберите «Файл» | Новый (Ctrl + N) из выпадающего меню.

На панели «Новый документ» выберите вкладку «Шаблоны». В разделе «Категория» выберите «AIR for Android» и выберите « 480×800 Android» в разделе «Шаблоны».

Нажав OK, вы создадите и настроите FLA, предназначенный для AIR for Android. Вы можете подтвердить это, изучив панель свойств рабочей области:

Из раздела «ПУБЛИКАЦИЯ» вы должны четко видеть, что ваш FLA настроен на использование проигрывателя AIR Android и что имеется ссылка для открытия настроек приложения и установщика AIR Android.

Закройте ваш FLA и откройте speedometer-artwork.fla из исходного кода загрузки. Теперь мы будем работать с этим FLA. Прежде чем продолжить, найдите подходящее место на жестком диске и сохраните его как speedometer.fla .

FLA имеет размер сцены 480 x 800, который соответствует разрешению экрана Google Nexus One, которое я использовал при написании и тестировании этого учебника. Однако не все устройства Android имеют одинаковое разрешение экрана. Например, Motorola Droid имеет разрешение экрана 480 х 854.

Если разрешение экрана вашего устройства отличается, измените размер сцены в соответствии с ним. Для этого нажмите кнопку « Изменить …» на панели «Свойства» в разделе «СВОЙСТВА»:

Откроется панель «Настройки документа». Измените ширину и высоту на этой панели и нажмите кнопку ОК.

Сохраните FLA.


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

Начнем с ознакомления с классом AIR Geolocation и вывода текущей скорости во временное текстовое поле.


Выберите Text Tool (T) и нарисуйте текстовое поле размером 460 x 167 на сцене.

Поместите текстовое поле в (10, 10). Убедитесь, что для текстового движка установлено значение «Классический текст», а поле имеет тип «Динамический текст». Назовите свой экземпляр текстового поля «metresPerSecond».

Я использовал шрифт Regular Droid Sans размером 140pt, однако, если у вас не установлен этот шрифт, вы можете использовать альтернативу, такую ​​как Arial. Я также решил показать рамку вокруг моего текстового поля.

Введите значение по умолчанию «0» в текстовое поле и выровняйте текст по центру.

Вот снимок вышеуказанных настроек.

Наконец нажмите кнопку « Вставить …» и вставьте цифровые символы шрифта. Нажмите ОК.

Теперь добавьте статическое текстовое поле шириной 375 пикселей и поместите его в (95, 177). Используйте размер шрифта 40pt. Я не беспокоился о границе вокруг этого текстового поля.

Введите «метров в секунду» в текстовое поле и выровняйте текст по правому краю.

Вот снимок настроек этого текстового поля.

Сохраните свой FLA.

Пришло время написать ActionScript для обновления динамического текстового поля с вашей скоростью.


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

Создайте новый файл ActionScript 3, выбрав «Файл | Новый … (Ctrl + N) в Flash Professional. Откроется панель «Новый документ».

На панели «Новый документ» щелкните вкладку «Общие» и выберите класс ActionScript 3.0. Нажмите ОК.

Добавьте к этому следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package
{
    import flash.display.Sprite;
    import flash.events.GeolocationEvent;
    import flash.sensors.Geolocation;
    import flash.text.TextField;
     
    public class Application extends Sprite
    {
        public var metresPerSecond :TextField;
        private var geolocation :Geolocation;
         
        public function Application()
        {
            geolocation = new Geolocation();
            geolocation.setRequestedUpdateInterval( 1000 );
            geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
        }
         
        private function handleGeolocationUpdate( e :GeolocationEvent ) :void
        {
            metresPerSecond.text = String( Math.round( e.speed ) );
        }
    }
}

Сохраните класс в том же месте, где находится ваш FLA, и назовите его Application.as .

Щелкните левой кнопкой мыши на сцене (не нажимайте ни на одно из текстовых полей) и установите для поля «Класс документа» на панели «Свойства» значение: Application .

В классе объявлены две переменные-члены. Вот они:

1
2
public var metresPerSecond :TextField;
private var geolocation :Geolocation;

Первый, metresPerSecond , имеет тип TextField и представляет собой динамическое текстовое поле, созданное на шаге 5. Второй, geolocation , будет использоваться для ссылки на экземпляр класса Geolocation .

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

Класс Geolocation находится в пакете flash.sensors . Мы также будем использовать класс GeolocationEvent , который был импортирован вместе с Geolocation :

1
2
import flash.events.GeolocationEvent;
import flash.sensors.Geolocation;

Использование класса Geolocation не так сложно. Сначала создается экземпляр и присваивается вашей переменной члена geolocation :

1
geolocation = new Geolocation();

Затем вы указываете, как часто вы хотите получать информацию об обновлениях с вашего телефона. Интервал обновления измеряется в миллисекундах — мы запрашивали обновление каждую секунду:

1
geolocation.setRequestedUpdateInterval( 1000 );

Наконец, мы подключаем обработчик событий, который будет вызываться каждый раз, когда доступна информация об обновлении. Это делается путем прослушивания события GeolocationEvent.UPDATE из вашего экземпляра geolocation :

1
geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );

Обработчик событий — это то, где текущая скорость пользователя получается и выводится в наше текстовое поле. Определение скорости — это простой случай извлечения значения из свойства GeolocationEvent's speed перед преобразованием его в строку:

1
2
3
4
private function handleGeolocationUpdate( e :GeolocationEvent ) :void
{
    metresPerSecond.text = String( Math.round( e.speed ) );
}

Это более или менее. Теперь у вас есть код, необходимый для прослушивания обновлений GPS и вывода скорости, с которой путешествует пользователь.

Однако следует отметить, что метод setRequestedUpdateInterval() используется только как подсказка для устройства. Фактическое время между обновлениями местоположения может быть больше или меньше, чем запрашиваемый интервал. Однако для целей данного руководства мы предполагаем, что устройство будет соблюдать предложенный интервал.

Вы можете найти более подробную информацию о классе Geolocation в Adobe LiveDocs .


Хорошо, давайте создадим и развернем ваш код на вашем телефоне.

Выбрать файл | AIR Android Settings … для вызова панели настроек приложения и установщика.

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

Заполните поля, доступные на этой вкладке, убедившись, что поля соответствуют тем, которые показаны на экране ниже:

Нажмите на вкладку Развертывание.

Установите тип развертывания Android на «Выпуск устройства» и убедитесь, что в разделе « После публикации» установлены оба флажка.

Далее вам нужно будет создать сертификат для вашего приложения. Это можно сделать, просто нажав кнопку « Создать …» рядом с полем «Сертификат».

Появится панель «Создать самоподписанный цифровой сертификат». Для первых трех полей просто введите свое имя. Выберите соответствующий код вашей страны проживания для четвертого поля. Например, если вы живете в Великобритании, выберите GB; если вы проживаете в США, выберите США. Вы можете найти полный список кодов стран здесь .

В полях «Пароль» и «Подтверждение пароля» введите пароль для вашего сертификата.

Наконец, нажмите кнопку «Обзор» и выберите папку на жестком диске, в которой вы хотите сохранить сертификат. Та же папка, что должна делать ваша FLA.

Нажмите OK, и файл сертификата P12 будет создан и сохранен. Вы вернетесь на панель «Настройки приложения и установщика».

Нажмите кнопку Обзор … рядом с полем Сертификат и выберите файл сертификата P12. В поле «Пароль» введите пароль, связанный с вашим сертификатом, и установите флажок «Запомнить пароль для этого сеанса».

Нажмите на вкладку Разрешения (мы будем игнорировать значки).

При написании приложений для Android вам необходимо четко указать, какие разрешения требуются вашему приложению при использовании. На данный момент нам нужно приложение для доступа к местоположению телефона. Для этого необходимо ACCESS_FINE_LOCATION разрешения ACCESS_FINE_LOCATION и ACCESS_COARSE_LOCATION .

Разрешение ACCESS_FINE_LOCATION позволяет вашему приложению получать доступ к данным GPS через класс Geolocation. Если датчик местоположения вашего телефона недоступен, то разрешение ACCESS_COARSE_LOCATION позволит вашему приложению вместо этого попытаться получить доступ к данным о местоположении WIFI и сотовой сети через класс Geolocation . Однако этот запасной вариант не так точен.

Нажмите OK и сохраните свой FLA.


Теперь мы готовы опубликовать FLA и развернуть его на своем телефоне.

Если вы еще этого не сделали, подключите устройство к компьютеру с помощью USB-кабеля.

Мы дали указание Flash CS5 запустить приложение на подключенном устройстве сразу после публикации. Поэтому вам необходимо заранее убедиться, что датчик GPS вашего устройства включен.

Точные настройки для этого могут отличаться на разных устройствах Android, но большинство пользователей смогут включить его через домашний экран:

Либо на главном экране нажмите клавишу меню и выберите «Настройки». В разделе «Настройки» выберите «Местоположение и безопасность». Отсюда выберите Использовать спутники GPS, чтобы включить GPS.

Теперь идите вперед и опубликуйте FLA, выбрав File | Опубликовать (Alt + Shift + F12).

Если все идет по плану, FLA опубликует, будет создан Android APK, и файл будет передан на ваше устройство и запущен.

Приложение должно сначала прочитать «0 метров в секунду». Выньте телефон на улицу и начните ходить или, что еще лучше, бегите Вы должны видеть, что экран обновляется каждую секунду с вашей текущей скоростью.

Если у вас нет устройства для тестирования, не беспокойтесь, мы рассмотрим это на шаге 12 — Имитация геолокации.

В настоящее время просто убедитесь, что ваш код собирается, выбрав Control | Тестовый фильм | во Flash Professional (Ctrl + Enter). В случае успеха SWF должен работать в окне AIR, хотя по очевидным причинам текстовое поле не будет обновляться со скоростью.

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


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

К счастью, AIR предоставляет механизм для сохранения экрана устройства с помощью NativeApplication systemIdleMode класса NativeApplication .

Сначала импортируйте NativeApplication и SystemIdleMode в класс документа, добавив следующие строки:

1
2
3
4
5
6
import flash.desktop.NativeApplication;
import flash.desktop.SystemIdleMode;
import flash.display.Sprite;
import flash.events.GeolocationEvent;
import flash.sensors.Geolocation;
import flash.text.TextField;

Теперь давайте добавим фактическую строку кода, которая заставляет экран бодрствовать, пока ваше приложение используется:

1
2
3
4
5
6
7
8
public function Application()
{
    NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
     
    geolocation = new Geolocation();
    geolocation.setRequestedUpdateInterval( 1000 );
    geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
}

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

Выбрать файл | Настройки Android AIR …. Перейдите на вкладку «Разрешения» и проверьте разрешения WAKE_LOCK и DISABLE_KEYGUARD :

Нажмите кнопку ОК, чтобы закрыть панель «Приложения и установщик». Сохраните свой FLA.

Опубликуйте и снова разверните свое приложение на телефоне (Alt + Shift + F12). Существующая версия приложения, работающего на вашем телефоне, будет автоматически закрыта, и будет запущена новая версия.

На этот раз он должен работать без подсветки.

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

Вы можете найти больше информации о NativeApplication и SystemIdleMode в Adobe LiveDocs .


Нажатие клавиши «Назад» или «Домой» на вашем телефоне выведет вас из приложения, но на самом деле оно не выйдет из приложения. Вместо этого Android заставляет приложения уходить в фоновый режим, а не останавливать их полностью.

Когда приложение AIR перемещается в фоновый режим, оно получает событие Event.DEACTIVATE а также снижает частоту кадров до 4 кадров в секунду. Тем не менее, по большей части, вы должны написать код, чтобы изящно перевести ваше приложение в спящий режим, который не излишне истощает ресурсы.

Это подчеркивается классом Geolocation , который продолжит отправлять события GeolocationEvent.UPDATE после перемещения приложения в фоновый режим.

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

В следующий раз, когда вы используете приложение (как правило, выбирая его из меню), оно будет снова перемещено на передний план и будет вести себя так, как если бы оно работало на переднем плане все время. Когда приложение AIR перемещается на передний план, оно получает событие Event.ACTIVATE и частота кадров возвращается к исходному значению.

Давайте проверим, что ваше приложение было перемещено в фоновый режим при выходе из него.

Опубликуйте и разверните приложение на своем телефоне (Alt + Shift + F12).

Как только приложение запустится, нажмите клавишу «Назад», чтобы перейти на рабочий стол. На главном экране нажмите клавишу меню и выберите «Настройки». В настройках выберите Приложения.

В разделе «Настройки приложений» выберите «Управление приложениями» и нажмите вкладку «Запуск». Вам будет показан список приложений, которые в данный момент работают на вашем устройстве. Прокрутите вниз, пока не найдете приложение Спидометр. Выбор значка приложения приведет вас к экрану «Информация о приложении», где вы сможете принудительно остановить его. Это убьет приложение, освободит память и поможет сэкономить заряд батареи.

Иди вперед и заставь приложение остановиться.


В зависимости от типа приложения, которое вы пишете, вам может не потребоваться запускать его в фоновом режиме при выходе пользователя.

На самом деле вы можете использовать ActionScript, чтобы принудительно закрыть приложение AIR (без отправки в фоновый режим), выполнив следующий вызов NativeApplication объекта NativeApplication :

1
NativeApplication.nativeApplication.exit();

Давайте на самом деле сделаем это с помощью приложения спидометра, перехватывая нажатия клавиш «Назад» и «Домой» и переопределяя их поведение по умолчанию. Давайте напишем некоторый код для обработки клавиши Back.

Сначала добавьте следующие два импорта в Application.as :

1
2
3
4
5
6
7
8
import flash.desktop.NativeApplication;
import flash.desktop.SystemIdleMode;
import flash.display.Sprite;
import flash.events.GeolocationEvent;
import flash.events.KeyboardEvent;
import flash.sensors.Geolocation;
import flash.text.TextField;
import flash.ui.Keyboard;

Теперь в конструкторе добавьте прослушиватель событий для захвата нажатий клавиш:

1
2
3
4
5
6
7
8
9
public function Application()
{
    NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
    NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
             
    geolocation = new Geolocation();
    geolocation.setRequestedUpdateInterval( 1000 );
    geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
}

При захвате нажатий клавиш в Flash Player мы обычно добавляем прослушиватель событий к объекту stage:

1
stage.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );

Однако при написании для AIR for Android вы должны добавить прослушиватель событий в объект NativeApplication :

1
NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );

Добавьте метод handleKeyDown() который вызывается при захвате KeyboardEvent.KEY_DOWN :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
private function handleKeyDown( e :KeyboardEvent ) :void
{
    switch( e.keyCode )
    {
        case Keyboard.BACK:
            NativeApplication.nativeApplication.exit();
            break;
         
        case Keyboard.SEARCH:
        case Keyboard.MENU:
            e.preventDefault();
            break;
    }
}

Этот метод определяет нажатую клавишу, проверяя свойство keyCode хранящееся в KeyboardEvent которое было передано handleKeyDown() .

Сами коды клавиш были замаскированы константами, предоставленными классом Keyboard . Код клавиши «Назад» представлен Keyboard.BACK .

По коду вы сможете увидеть, что если нажата кнопка «Назад», выполняется вызов, чтобы заставить приложение выйти, а не перемещаться в фоновый режим:

1
2
3
case Keyboard.BACK:
    NativeApplication.nativeApplication.exit();
    break;

Метод handleKeyDown() также ищет пользователя, нажимающего клавиши «Поиск» или «Меню», и предотвращает его поведение по умолчанию, preventDefault() метод preventDefault() события:

1
2
3
4
case Keyboard.SEARCH:
case Keyboard.MENU:
    e.preventDefault();
    break;

Это заблокирует виртуальную клавиатуру Android от появления, если пользователь удерживает нажатой клавишу Меню, и заблокирует приложение Google Voice, когда пользователь удерживает клавишу поиска. Ни один из которых нам не требуется для приложения спидометра.

Мы еще не обратились к ключу Home. В отличие от «Назад», «Поиск» и «Меню», вы фактически не можете перехватить клавишу «Домой» через событие KeyboardEvent.KEY_DOWN . Вместо этого при нажатии клавиши Event.DEACTIVATE будет отправлено событие Event.DEACTIVATE , которое вы можете прослушать. Это событие отправляется непосредственно перед перемещением приложения в фоновый режим. Вместо этого вы можете прослушать событие и заставить приложение выйти.

Добавьте код для прослушивания события Event.DEACTIVATE :

1
2
NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );

Вам также необходимо импортировать класс Event :

1
2
3
import flash.display.Sprite;
import flash.events.Event;
import flash.events.GeolocationEvent;

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

1
2
3
4
private function handleDeactivate( e :Event ) :void
{
    NativeApplication.nativeApplication.exit();
}

Сохраните Application.as затем сохраните свой FLA.

Хорошо, теперь у нас должно быть приложение, которое закрывается, когда пользователь нажимает клавиши «Назад» или «Домой», а не переключается на фон и разряжает батарею.

Опубликуйте приложение (Alt + Shift + F12) и, когда оно запустится на вашем устройстве, нажмите клавишу Назад или Домой, чтобы выйти. Теперь перейдите к экрану «Управление приложениями» (через «Настройки») на устройстве Android. Выберите вкладку «Бег» и убедитесь, что спидометр отсутствует в списке.


Как вы можете себе представить, тестирование приложения с поддержкой GPS может стать довольно утомительным, поскольку вам нужно постоянно двигаться, если вы хотите получать полезные данные из класса Geolocation . Для тех, кто работает с приложением во Flash CS5, тестирование с фактическими данными о местоположении пока невозможно.

Давайте попробуем решить обе эти проблемы, написав код, который имитирует класс Geolocation с использованием предварительно записанных данных GPS. Этот шаг даст вам возможность использовать некоторые классы файловой системы, предоставляемые AIR.

Вы найдете двоичный файл по адресу source / gps.dat, который содержит набор скоростей, измеренных с интервалом в одну секунду от моего Google Nexus One, когда я ехал на машине. Мы напишем класс, который имеет тот же общедоступный API, что и класс Geolocation но читает значения из gps.dat, а не считывает данные с датчика местоположения вашего телефона.


Сначала давайте скопируем gps.dat в папку пользователя на вашем рабочем столе, а также в телефон, чтобы протестировать приложение на вашем устройстве, не полагаясь на его действительный модуль GPS.

Для рабочего стола вот куда скопировать файл gps.dat:

  • Windows Vista и Windows 7: C: \ Users \ ваше_имя_пользователя \
  • Windows XP: C: \ Documents and Settings \ ваше_имя_пользователя \
  • Mac OS X: Macintosh HD / Пользователи / ваше_имя_пользователя /

Для вашего телефона Android скопируйте файл gps.dat в корень SD-карты вашего телефона. Для этого подключите ваше устройство к рабочему столу через USB-кабель. Откройте панель уведомлений на устройстве, коснувшись строки состояния и потянув вниз.

Внутри панели уведомлений вы должны увидеть постоянный раздел. Нажмите значок USB-подключения в этом разделе, чтобы перейти к экрану USB Mass Storage. На этом экране нажмите кнопку «Включить USB-накопитель».

Теперь вы можете исследовать SD-карту устройства со своего рабочего стола. В Windows вам будет предоставлена ​​возможность просмотра файлов на SD-карте с помощью проводника Windows. На появившейся панели выбора просто выберите «Открыть папку для просмотра файлов с помощью проводника Windows».

В Mac OS X на рабочем столе появится значок, представляющий ваше устройство. Просто дважды щелкните значок, чтобы открыть окно Finder. Или откройте окно Finder в Dock и выберите устройство из списка DEVICES в левой части окна Finder.

Теперь скопируйте файл gps.dat в корневую папку на SD-карте.

По завершении копирования отключите USB-накопитель, нажав кнопку «Отключить USB-накопитель» на экране USB Mass Storage вашего устройства.

Теперь вы готовы написать код для чтения этих данных.


Создайте новый класс ActionScript и добавьте в него следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package
{
    import flash.events.EventDispatcher;
 
    public class GeolocationSimulate
        extends EventDispatcher
    {
        public function GeolocationSimulate()
        {
            /** @todo: Open gps.dat file for reading and set a timer to continually read from it.
        }
         
        public function setRequestedUpdateInterval( interval :Number ) :void
        {
            /** @todo: Set the interval used to read each speed.
        }
    }
}

Сохраните класс в том же месте, где находится ваш FLA, и назовите его GeolocationSimulate.as .

Класс очень неполный в данный момент. Обратите внимание на комментарии @todo в некоторых местах. Это указывает на функциональность, которую мы еще должны добавить. Однако прежде чем мы это сделаем, необходимо объяснить, что у нас есть в настоящее время.

По сути, мы пишем класс, который придерживается того же открытого интерфейса, что и класс Geolocation в AIR SDK. Если вы посмотрите на Live Docs for Geolocation вы заметите, что API имеет полный список открытых методов.

Однако для целей данного руководства мы на самом деле пользуемся лишь небольшим подмножеством открытого API-интерфейса Geolocation's , поэтому нам нужно только обеспечить, чтобы наш класс GeolocationSimulate предоставлял функциональные возможности для методов из Geolocation которые мы фактически используем.

Вот список этих методов:

  • setRequestedUpdateInterval()
  • addEventListener()

Глядя на нашу текущую реализацию GeolocationSimulate вы можете подумать, что мы включили только один из этих методов — может показаться, что addEventListener() отсутствует в классе. Однако если вы посмотрите немного поближе, то увидите, что GeolocationSimulate расширяет класс EventDispatcher API-интерфейса Flash.

Класс EventDispatcher предоставляет GeolocationSimulate addEventListener() а также предоставляет функциональные возможности, позволяющие нашему классу в конечном итоге отправлять события — нам потребуется это, чтобы наш класс GeolocationSimulate отправил событие GeolocationEvent.UPDATE которое мы прослушиваем из Application.as . Вот код из Application.as снова в качестве напоминания:

1
2
3
geolocation = new Geolocation();
geolocation.setRequestedUpdateInterval( 1000 );
geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );

По сути, мы хотим подключить наш новый класс GeolocationSimulate к приведенному выше коду и заставить его работать так, как если бы он был настоящим классом Geolocation . Единственная разница должна заключаться в том, что GeolocationSimulate должен отправлять событие GeolocationEvent.UPDATE которое содержит поддельные данные, периодически извлекаемые из файла gps.dat на вашем телефоне или рабочем столе.

Хотя это далеко не закончено, давайте подключим наш новый класс к Application.as .

Сначала измените следующий код, чтобы создать экземпляр GeolocationSimulate а не Geolocation :

01
02
03
04
05
06
07
08
09
10
11
12
13
public var metresPerSecond :TextField;
private var geolocation :GeolocationSimulate;
         
public function Application()
{
    NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
    NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
    NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
             
    geolocation = new GeolocationSimulate();
    geolocation.setRequestedUpdateInterval( 1000 );
    geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
}

Публикуйте и тестируйте свой код в Flash CS5 на данный момент, выбрав Control | Тестовый фильм | во Flash Professional (Ctrl + Enter). Он пока ничего не сделает, но должен хотя бы опубликовать.


Пора начинать добавлять некоторые функциональные возможности в методы-заглушки в классе GeolocationSimulate . Давайте сосредоточимся на написании кода для setRequestedUpdateInterval() .

По сути, мы хотим, чтобы класс периодически считывал значение скорости из gps.dat и отправлял событие GeolocationEvent.UPDATE содержащее это значение, любым слушателям.

Мы можем сделать это, добавив экземпляр Timer и установив его свойство delay в setRequestedUpdateInterval() . Внесите следующие изменения в свой код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package
{
    import flash.events.EventDispatcher;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
 
    public class GeolocationSimulate
        extends EventDispatcher
    {
        static private const DEFAULT_DELAY :Number = 1000;
         
        private var timer :Timer;
         
        public function GeolocationSimulate()
        {
            /** @todo: Open gps.dat file for reading.
            timer = new Timer( DEFAULT_DELAY );
            timer.addEventListener( TimerEvent.TIMER, handleTimer );
            timer.start();
        }
         
        public function setRequestedUpdateInterval( interval :Number ) :void
        {
            timer.delay = interval;
        }
         
        private function handleTimer( e :TimerEvent ) :void
        {
            /** @todo: Read the next speed from gps.dat.
        }
    }
}

Внутри конструктора мы создали экземпляр класса Timer и присвоили его переменной-члену с именем timer . При создании экземпляра объекта Timer мы указали, что он должен непрерывно повторяться с интервалом в одну секунду (1000 миллисекунд). Слушатель событий с именем handleTimer() также был добавлен в таймер и будет вызываться при каждом повторении.

В настоящее время метод handleTimer() ничего не будет делать. В конце концов он будет читать следующее значение скорости из gps.dat.

Сохраните GeolocationSimualte.as .


Давайте проверим текущую версию GeolocationSimulate , убедившись, что код таймера работает. Мы можем сделать это, добавив простую инструкцию trace в метод handleTimer() и handleTimer() его в окне вывода Flash.

Добавьте следующий оператор трассировки:

1
2
3
4
5
private function handleTimer( e :TimerEvent ) :void
{
    /** @todo: Read the next speed from gps.dat.
    trace( «GeolocationSimulate::handleTimer()» );
}

Опубликуйте и протестируйте свой код в Flash CS5, выбрав Control | Тестовый фильм | во Flash Professional (Ctrl + Enter). Если все идет по плану, вы должны видеть следующее, отслеживаемое в окне вывода каждую секунду:

1
GeolocationSimulate::handleTimer()

Давайте сейчас протестируем код на вашем Android-устройстве.

Чтобы помочь нам, мы будем использовать инструмент Android Debug Bridge (abd), который можно использовать для фильтрации и просмотра информации журналов из различных приложений на вашем устройстве, включая операторы трассировки, поступающие из ваших приложений AIR.

Adb — это инструмент командной строки, который можно найти рядом с вашей установкой Flash CS5. Вот где найти adb в Windows или Mac OS X:

  • Windows Vista и Windows 7: C: \ Program Files (x86) \ Adobe \ Adobe Flash CS5 \ Android \ tools \ adb.exe
  • Windows XP: C: \ Program Files \ Adobe \ Adobe Flash CS5 \ Android \ tools \ adb.exe
  • Mac OS X: / Приложения / Adobe Flash CS5 / Android / Инструменты / ADB

Перейдите к подразделу ниже, относящемуся к вашей ОС, затем перейдите к подразделу «Запуск adb» чуть ниже.

Если вы используете Windows 7 или Vista, откройте проводник Windows и перейдите в папку: C: \ Program Files (x86) \ Adobe \ Adobe Flash CS5 \ Android. Теперь удерживайте Shift и щелкните правой кнопкой мыши на папке инструментов. В раскрывающемся меню выберите «Открыть окно команд», чтобы открыть окно команд.

Для тех, кто использует Windows XP, нажмите кнопку « Пуск» и выберите « Выполнить …», чтобы открыть окно «Выполнить»:

В окне «Выполнить» введите « cmd »:

Нажмите OK, чтобы открыть командное окно. Теперь перейдите в папку, где хранится ADB, введя следующее:

1
cd C:\Program Files\Adobe\Adobe Flash CS5\Android\tools

Пользователям Max OS X придется открыть окно терминала. Для этого откройте стек приложений и найдите папку Utilities:

Нажмите на папку «Утилиты» и найдите значок «Терминал»:

Нажмите на значок терминала, чтобы открыть окно терминала.

Из окна терминала перейдите в папку, где хранится adb, введя следующее:

1
cd ‘/Applications/Adobe Flash CS5/Android/tools’

Из командного окна мы можем запустить adb и выполнить для logcat команду logcat , чтобы начать получать информацию журнала, поступающую с вашего устройства Android. Мы заинтересованы только в получении информации о трассировке из приложения AIR, поэтому необходимо применить фильтр.

Убедитесь, что ваше устройство Android подключено через порт USB.

Если вы используете Windows, введите в командной строке следующее для получения информации журнала из приложения AIR:

1
adb logcat air.speedometer:I *:S

Пользователи Mac OS X должны ввести в окно терминала следующее:

1
./adb logcat air.speedometer:I *:S

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

В Flash CS5 выберите Файл | Настройки Android AIR …. На панели «Настройки приложения и установщика» перейдите на вкладку «Развертывание» и установите переключатель «Отладка».

Нажмите OK, чтобы закрыть панель.

Сохраните FLA.

Теперь опубликуйте приложение, выбрав Файл | Опубликовать (Alt + Shift + F12).

При запуске приложения на вашем устройстве может появиться следующее диалоговое окно:

Если это произойдет, просто нажмите Отмена, чтобы закрыть диалоговое окно и возобновить выполнение приложения.

Командное окно, из которого работает adb, теперь должно получать информацию трассировки из вашего класса GeolocationSimulate . Вывод в командном окне должен выглядеть примерно так:

1
I/air.Speedometer( 1821): GeolocationSimulate::handleTimer()

Существует много способов отладки приложений AIR для Android, причем adb является одним из вариантов, и, возможно, самым простым. Вы можете найти исчерпывающую документацию по adb на официальном сайте разработчиков Android .

В качестве альтернативы вы можете рассмотреть возможность использования монитора отладки Dalvik или запуска сеанса удаленной отладки непосредственно из Flash Pro. Однако из-за ограниченного объема этого руководства мы будем придерживаться использования adb через командное окно.

Выйдите из приложения, чтобы в командной строке не появлялось больше операторов трассировки.

Хорошо, мы можем продолжить добавлять функциональность в GeolocationSimulate .


Теперь, когда мы уверены, что код таймера работает, нам нужно добавить некоторые функции, которые на самом деле считывают поддельные данные GPS из gps.dat. Но сначала позвольте мне объяснить формат данных, хранящихся в gps.dat.

По сути, gps.dat — это двоичный файл, который состоит из набора чисел с плавающей запятой. Числа с плавающей запятой представлены типом числа во Flash, и каждое из этих чисел с плавающей запятой представляет значение скорости, измеренное в метрах в секунду.

Adobe AIR SDK предоставляет класс FileStream который можно использовать для открытия, чтения и записи в двоичные файлы. Для нашего класса GeolocationSimulate нам потребуется открыть и прочитать данные из файла — запись не требуется.

Начнем с объявления закрытой переменной-члена filestream в классе GeolocationSimulate Мы будем использовать эту переменную для хранения ссылки на объект FileStream :

1
2
private var filestream :FileStream;
private var timer :Timer;

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

1
2
static private const DEFAULT_DELAY :Number = 1000;
static private const FILE :String = «gps.dat»;

Следующим шагом является создание экземпляра объекта FileStream в конструкторе класса и открытие двоичного файла для чтения. Вот код:

01
02
03
04
05
06
07
08
09
10
11
public function GeolocationSimulate()
{
    timer = new Timer( DEFAULT_DELAY );
    timer.addEventListener( TimerEvent.TIMER, handleTimer );
    timer.start();
 
    var file :File = File.userDirectory;
    file = file.resolvePath( FILE );
    filestream = new FileStream();
    filestream.open( file, FileMode.READ );
}

Сначала создается объект File который указывает на местоположение gps.dat на вашем компьютере и устройстве Android.

Класс File имеет свойства, которые имеют значимые значения в разных операционных системах. Например, Windows, Mac OS X и Android имеют разные собственные пути к каталогу пользователя. Однако мы можем легко получить доступ к папке пользователя независимо от операционной системы, используя File.userDirectory как показано ниже:

1
var file :File = File.userDirectory;

Получив дескриптор пользовательской папки, мы просто используем метод resolvePath() класса File , чтобы создать путь к файлу gps.dat:

1
file = file.resolvePath( FILE );

Две строки кода, описанные выше, эффективно определяют путь к gps.dat в Windows, Mac и Android. Обратите внимание на использование константы FILE , которая содержит имя файла.

Теперь, когда у нас есть путь к файлу gps.dat, мы можем создать объект FileStream и открыть файл. Вот две строки кода, которые отвечают за это:

1
2
filestream = new FileStream();
filestream.open( file, FileMode.READ );

При открытии файла вам необходимо явно указать, открываете ли вы файл для чтения из него, записи в него или обоих.В нашем случае мы просто хотим прочитать из файла, что делается передачей FileMode.READв качестве аргумента open()метода.

Вы можете увидеть полный список констант, доступных FileModeна Adobe LiveDocs.

Все, что осталось сделать — это фактически прочитать следующее значение скорости из файла при каждом обновлении таймера. Добавьте следующий код в handleTimer()метод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
private function handleTimer( e :TimerEvent ) :void
{
    if( filestream != null )
    {
        var speed :Number;
 
        if( filestream.bytesAvailable )
        {
            speed = filestream.readFloat();
        }
        else
        {
            filestream.position = 0;
            speed = filestream.readFloat();
        }
         
        */
    }
}

Приведенный выше код считывает следующую доступную скорость из файла и сохраняет ее в локальной переменной с именем speed.

Прежде чем скорость может быть считана из файла, выполняется проверка, достигли ли мы конца файла или нет. Это делается путем считывания filestreamобъекта bytesAvailableсобственности. Если достигнут конец файла, это bytesAvailableбудет 0означать, что больше нет данных для чтения. Если это так , то мы просто начинаем чтение данных с самого начала файла снова с помощью установки filestreamобъекта positionсвойства 0. Вот фрагмент кода, ответственного за это:

1
2
3
4
5
6
7
8
9
if( filestream.bytesAvailable )
{
     speed = filestream.readFloat();
}
else
{
     filestream.position = 0;
     speed = filestream.readFloat();
}

Само значение скорости читается из файла путем вызова readFloat()метода. Это читает следующее доступное значение с плавающей запятой из файла.

Перед тестированием вашей последней версии GeolocationSimulateкласса вам нужно добавить несколько импортов, чтобы Flash знал, где найти различные используемые классы файлового потока:

1
2
3
4
5
6
import flash.events.EventDispatcher;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.Timer;

Теперь давайте проверим последнюю версию класса, добавив оператор trace в конце handleTimer()метода:

1
2
*/
trace( "GeolocationSimulate::handleTimer() speed: " + speed );

Это отследит последнее значение скорости, которое было прочитано из файла gps.dat.

Теперь сохраните класс и протестируйте последнюю версию приложения как во Flash CS5, так и на устройстве. Хотя текстовое поле «метров в секунду» еще не обновится (мы вернемся к этому на следующем шаге), каждую секунду вы должны видеть оператор трассировки с последним значением скорости, полученным из gps.dat.


Когда мы использовали Geolocationкласс в шагах 4-11, вы, возможно, помните, что он отправлял GeolocationEvent.UPDATEсобытие каждый раз, когда датчик местоположения вашего устройства получал новые данные GPS. Из этого события мы смогли извлечь скорость и отобразить ее в текстовом поле.

Мы слушали это событие и обновляли текстовое поле внутри Applicationкласса.

Напомним, что здесь приведен код Applicationконструктора Geolocationкласса, который создал экземпляр класса и настроил прослушиватель событий:

1
2
3
geolocation = new GeolocationSimulate();
geolocation.setRequestedUpdateInterval( 1000 );
geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );

И вот фактический метод, который вызывается всякий раз, когда Geolocationобъект отправляет GeolocationEvent.UPDATEсобытие:

1
2
3
4
private function handleGeolocationUpdate( e :GeolocationEvent ) :void
{
    metresPerSecond.text = String( Math.round( e.speed ) );
}

Чтобы наш GeolocationSimulateкласс полностью имитировал Geolocationего, он также должен отправить GeolocationEvent.UPDATEсобытие. Если этого не произойдет, то наш Applicationкласс не сможет узнать о наличии новых данных GPS и поэтому не сможет отображать текущую скорость в своем текстовом поле.

К счастью, отправление события из GeolocationSimulateтривиально. Если вы оглянетесь на Шаг 14, то вспомните, что класс расширяет класс Flash EventDispatcher. Это обеспечивает GeolocationSimulateсредства для отправки событий через dispatchEvent()метод.

Удалите оператор трассировки, который вы добавили на предыдущем шаге, и добавьте следующий код в конец handleTimer()внутри GeolocationSimulate.as:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private function handleTimer( e :TimerEvent ) :void
{
    if( filestream != null )
    {
        var speed :Number;
 
        if( filestream.bytesAvailable )
        {
            speed = filestream.readFloat();
        }
        else
        {
            filestream.position = 0;
            speed = filestream.readFloat();
        }
 
        dispatchEvent(
            new GeolocationEvent(
                GeolocationEvent.UPDATE,
                false,
                false,
                0,
                0,
                0,
                0,
                0,
                speed,
                0,
                0
            )
        );
    }
}

dispatchEvent()Метод ожидает один аргумент — объект типа Event. Все события внутри Flash выходят из Eventкласса. Особое событие, которое нас интересует, — это GeolocationEvent, которое было создано и передано dispatchEvent()выше.

Конструктор GeolocationEventкласса ожидает одиннадцать аргументов, два из которых нас интересуют — первый и девятый параметры.

Первый параметр — это тип события, которое в этом случае должно быть типа GeolocationEvent.UPDATE. Девятый параметр — текущая скорость в метрах в секунду. Для этого мы передаем нашу локальную переменную с именем speed.

Остальные параметры мы заполняем значениями по умолчанию, указанными в LiveDocs .

Добавьте оператор импорта, чтобы Flash знал, где найти GeolocationEventкласс:

1
2
3
import flash.events.EventDispatcher;
import flash.events.GeolocationEvent;
import flash.events.TimerEvent;

Всякий раз, когда доступно новое значение скорости, GeolocationSimulateтеперь может отправлять событие любому слушателю. Сохраните файл класса.

Вот текущая версия класса для вашей справки:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package
{
    import flash.events.EventDispatcher;
    import flash.events.GeolocationEvent;
    import flash.events.TimerEvent;
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.utils.Timer;
 
    public class GeolocationSimulate
        extends EventDispatcher
    {
        static private const DEFAULT_DELAY :Number = 1000;
        static private const FILE :String = "gps.dat";
         
        private var filestream :FileStream;
        private var timer :Timer;
         
        public function GeolocationSimulate()
        {
            timer = new Timer( DEFAULT_DELAY );
            timer.addEventListener( TimerEvent.TIMER, handleTimer );
            timer.start();
             
            var file :File = File.userDirectory;
            file = file.resolvePath( FILE );           
            filestream = new FileStream();
            filestream.open( file, FileMode.READ );
        }
         
        public function setRequestedUpdateInterval( interval :Number ) :void
        {
            timer.delay = interval;
        }
         
        private function handleTimer( e :TimerEvent ) :void
        {
            if( filestream != null )
            {
                var speed :Number;
 
                if( filestream.bytesAvailable )
                {
                    speed = filestream.readFloat();
                }
                else
                {
                    filestream.position = 0;
                    speed = filestream.readFloat();
                }
             
                dispatchEvent(
                    new GeolocationEvent(
                        GeolocationEvent.UPDATE,
                        false,
                        false,
                        0,
                        0,
                        0,
                        0,
                        0,
                        speed,
                        0,
                        0
                    )
                );
            }
        }
    }
}

Теперь протестируйте последнюю версию приложения как во Flash CS5, так и на устройстве. В Flash CS5 и на вашем Android-устройстве вы увидите обновление текстового поля «метров в секунду» с самыми последними скоростями, используя значения, хранящиеся в gps.dat.

Это идеально, так как теперь вы можете тестировать из Flash CS5 и на вашем устройстве без необходимости фактически никуда идти (или даже включать GPS-приемник вашего телефона).


При запуске последней версии приложения вы можете заметить некоторые специфические скорости чтения из gps.dat. Вот значения для первых пятнадцати секунд пути:

2, 128 , 5, 6, 128 , 7, 128 , 7, 128 , 8, 6, 5, 128 , 7, 9

Должно быть ясно, что в данных есть странные скачки. Например, второе значение, указанное выше, предполагает, что моя машина разгоняется с 2 метров в секунду до 128 метров в секунду. Данные утверждают, что за одну секунду скорость моей машины увеличилась примерно на 286 миль в час. Я не водил ракету, и что случилось?

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

Я не удалил эти ошибочные значения по очень веской причине. При написании приложений, использующих преимущества GPS, вы никогда не должны ожидать, что данные будут идеальными, и вместо этого должны писать код для обработки таких ошибок.

Мы пока не будем беспокоиться об ошибках в данных, но мы рассмотрим проблему во второй части этого руководства.


Итак, у нас есть полностью функциональная симуляция, Geolocationно как нам поменять местами симуляцию и реальную версию класса?

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

Например, чтобы перейти от GeolocationSimulateобратно к Geolocationвам, измените эту строку:

1
private var geolocation :GeolocationSimulate;

в

1
private var geolocation :Geolocation;

и эта строка:

1
geolocation = new GeolocationSimulate();

в

1
geolocation = new Geolocation();

Поскольку вы, несомненно, можете оценить, что это может быстро стать утомительным и стать склонным к ошибкам, так как вы постоянно переключаетесь между ними во время тестирования.

Другой, и, возможно, более разумный подход заключается в использовании двух переменных-членов в Applicationклассе: одна содержит ссылку на Geolocationдругую, а другая указывает на GeolocationSimulate. Вы также можете объявить константу, которая определяет, какую версию вы хотите использовать. Вот пример:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package
{
    //snip
     
    public class Application extends Sprite
    {
        static private const REAL_GEOLOCATION :Boolean = true;
         
        public var metresPerSecond :TextField;
        private var geolocation :Geolocation;
        private var geolocationSimulate :GeolocationSimulate;
         
        public function Application()
        {
            NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
            NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
            NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
             
            if( REAL_GEOLOCATION )
            {
                geolocation = new Geolocation();
                geolocation.setRequestedUpdateInterval( 1000 );
                geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
            }
            else
            {
                geolocationSimulate = new GeolocationSimulate();
                geolocationSimulate.setRequestedUpdateInterval( 1000 );
                geolocationSimulate.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
            }
        }
 
        //snip
}

Изменяя значение REAL_GEOLOCATIONконстанты с trueна falseдо публикации, вы можете легко переключаться между использованием Geolocationкласса AIR и вашего собственного GeolocationSimulateкласса.

Честно говоря, это все еще не совсем удовлетворительное решение.

Учитывая и то, Geolocationи другое GeolocationSimulateпредоставляют одинаковые открытые методы, необходимость в двух отдельных переменных-членах далека от идеальной. Было бы хорошо, если бы мы могли как-то иметь единственную переменную-член, которая могла бы указывать на экземпляр Geolocationили GeolocationSimulate.

К счастью, это может быть достигнуто с помощью интерфейсов.

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

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

По сути то , что мы пытаемся сделать , это определить общий публичный API , что как Geolocationи GeolocationSimulateмогут договориться. Другими словами, мы ищем общедоступные методы в обоих Applicationклассах.

Вот они:

  • public function setRequestedUpdateInterval( interval :Number ) :void
  • public function addEventListener( type :String, listener :Function, useCapture :Boolean = false, priority :int = 0, useWeakReference :Boolean = false ):void

Теперь, когда мы знаем публичные методы, которые наши два класса должны предоставить (и уже сделали), давайте создадим интерфейс для них.

Создайте новый файл ActionScript 3 и добавьте в него следующий код:

1
2
3
4
5
6
7
8
9
package
{
    import flash.events.IEventDispatcher;
     
    public interface IGeolocation extends IEventDispatcher
    {
        function setRequestedUpdateInterval( interval :Number ) :void;
    }
}

Сохраните файл как IGeolocation.as. Это соглашение префикс имени интерфейса с заглавной буквы «I».

Вы, возможно, уже заметили, что addEventListener()явно не указан в интерфейсе. Не волнуйся, я не забыл об этом. Вместо этого я решил расширить IEventDispatcherинтерфейс, который предоставляется Flash SDK и включает в себя addEventListener(). Это фактически заставит все публичные методы, перечисленные внутри, IEventDispatcherбыть частью IGeolocation'sинтерфейса. Это, однако, не является проблемой, так как Geolocationи GeolocationSimulateрасширяет EventDispatcherкласс, и поэтому уже содержит реализации для всех этих методов.

Также стоит отметить, что ключевое слово public явно не использовалось для объявления setRequestedUpdatInterval()внутри интерфейса. Внутри интерфейса могут быть объявлены только открытые методы, поэтому publicключевое слово не обязательно, хотя вы можете использовать его, если хотите.

Теперь, когда у вас есть свой интерфейс, вам нужно сделать оба Geolocationи GeolocationSimulateпринять его. Давайте начнем с GeolocationSimulate.

Добавьте следующую строку кода:

1
2
3
4
public class GeolocationSimulate
    extends EventDispatcher
    implements IGeolocation
{

Это оно!Требуется только одна строка кода. Мы использовали implementsключевое слово, чтобы заставить класс реализовать методы, перечисленные в IGeolocationинтерфейсе.

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

Теперь есть небольшая проблема с Geolocationклассом. Он был предоставлен AIR SDK, и нет никакого способа напрямую изменить определение этого класса. Поэтому мы не можем просто загрузить Geolocationкласс в текстовый редактор и заставить его реализовать IGeolocation.

Вместо этого мы собираемся создать новый класс, который расширяет Geolocationи заставляет этот новый класс реализовываться IGeolocation. Это не так плохо, как кажется, и потребует всего несколько строк кода.

Создайте новый класс и добавьте в него следующее:

01
02
03
04
05
06
07
08
09
10
package
{
    import flash.sensors.Geolocation;
     
    public class GeolocationReal
        extends Geolocation
        implements IGeolocation
    {
    }
}

Сохранить класс как GeolocationReal.as.

Этот новый класс обладает всеми функциями, Geolocationно также и реализует IGeolocation. Отныне мы будем использовать GeolocationRealвместо Geolocationнашего кода.

Мы почти закончили, и должно стать понятно, почему мы используем интерфейсы.

Хотя интерфейс не имеет своей собственной реализации, он может использоваться как тип данных, и именно здесь сила интерфейсов станет очевидной. Внутри Applicationкласса мы можем создать единственную переменную-член, которую можно использовать для ссылки на оба GeolocationRealи GeolocationSimulate. Эта переменная-член будет иметь тип IGeolocation.

Во-первых, удалите оператор импорта для flash.sensors.Geolocationfrom, Application.asпоскольку теперь мы будем использовать GeolocationRealего вместо:

1
2
3
import flash.events.KeyboardEvent;
import flash.sensors.Geolocation;
import flash.text.TextField;

Теперь внесите следующие изменения в класс и сохраните его:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package
{
    import flash.desktop.NativeApplication;
    import flash.desktop.SystemIdleMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.GeolocationEvent;
    import flash.events.KeyboardEvent;
    import flash.text.TextField;
    import flash.ui.Keyboard;
     
    public class Application extends Sprite
    {
        static private const GEOLOCATION_REAL :Boolean = false;
         
        public var metresPerSecond :TextField;
        private var geolocation :IGeolocation;
         
        public function Application()
        {
            NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
            NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
            NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
             
            if( GEOLOCATION_REAL )
            {
                geolocation = new GeolocationReal();
                geolocation.setRequestedUpdateInterval( 1000 );
                geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
            }
            else
            {
                geolocation = new GeolocationSimulate();
                geolocation.setRequestedUpdateInterval( 1000 );
                geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
            }
        }
         
        private function handleGeolocationUpdate( e :GeolocationEvent ) :void
        {
            metresPerSecond.text = String( Math.round( e.speed ) );
        }
         
        private function handleKeyDown( e :KeyboardEvent ) :void
        {
            switch( e.keyCode )
            {
                case Keyboard.BACK:
                    NativeApplication.nativeApplication.exit();
                    break;
                 
                case Keyboard.SEARCH:
                case Keyboard.MENU:
                    e.preventDefault();
                    break;
            }
        }
 
        private function handleDeactivate( e :Event ) :void
        {
            NativeApplication.nativeApplication.exit();
        }
    }
}

Нам нужно сделать еще одну вещь, но сначала протестируйте текущую версию FLA как на рабочем столе, так и на телефоне Android. Установите для GEOLOCATION_REALконстанты значение true, если вы хотите проверить с помощью датчика GPS вашего телефона (не забудьте активировать GPS на своем устройстве перед запуском приложения), в противном случае установите его falseна использование класса симуляции.

Благодаря использованию IGeolocationинтерфейса geolocationпеременная-член может представлять экземпляр класса GeolocationRealили GeolocationSimulate. Это будет продолжаться до тех пор, пока вы будете вызывать только geolocationпеременные-члены, которые принадлежат IGeolocation. Любая попытка вызвать методы, которые принадлежат GeolocationRealили GeolocationSimulateнет, IGeolocationприведет к ошибке компиляции при публикации.


На предыдущем этапе я упомянул, что я хотел бы, чтобы вы сделали еще одну вещь.

Учитывая, что только GeolocationRealили GeolocationSimulateможет быть использовано в любой момент времени, кажется несколько расточительным, что оба фактически скомпилированы в окончательный опубликованный SWF. Было бы идеально, если GeolocationSimulateбы мы на самом деле не были включены в выходной SWF-файл, если бы мы намеревались его использовать, GeolocationRealи наоборот.

С момента появления Flash CS4 условная компиляция стала доступна для разработчиков Flash. Условная компиляция позволяет использовать константы конфигурации, чтобы определять, какой код на самом деле включен в опубликованный SWF. Другими словами, условная компиляция позволяет включать и выключать блоки кода по всему проекту.

Поскольку мы будем использовать условную компиляцию, мы можем удалить GEOLOCATION_REALконстанту, которую вы использовали, чтобы решить, создавать ли ее экземпляр GeolocationRealили GeolocationSimulate. Константы, используемые для условной компиляции, задаются на панели «Параметры публикации», а не в ActionScript.

Давайте удалим строки кода из Applicationкласса, которые больше не потребуются. Вы можете увидеть их ниже жирным шрифтом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static private const GEOLOCATION_REAL :Boolean = false;
 
public var metresPerSecond :TextField;
private var geolocation :IGeolocation;
 
public function Application()
{
    NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
    NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
    NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
     
    if( GEOLOCATION_REAL )
    {
        geolocation = new GeolocationReal();
        geolocation.setRequestedUpdateInterval( 1000 );
        geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
    }
    else
    {
        geolocation = new GeolocationSimulate();
        geolocation.setRequestedUpdateInterval( 1000 );
        geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
    }
}

Теперь во Flash CS5 выберите File | Параметры публикации …. Откроется панель «Параметры публикации».

На панели «Параметры публикации» выберите вкладку «Flash»:

Нажмите на кнопку Настройки … справа от опции Script :. Откроется панель «Дополнительные параметры ActionScript 3.0»:

Нажмите на вкладку Константы конфигурации:

Отсюда нажмите на символ плюс, чтобы добавить константу конфигурации. Назовите константу CONFIG::GEOLOCATION_REALи присвойте ей значение false.

Добавьте вторую конфигурационную константу с именем CONFIG::GEOLOCATION_SIMULATEи присвойте ей значение true.

Панель констант конфигурации теперь должна выглядеть так:

Нажмите кнопку «ОК», чтобы закрыть панель «Дополнительные параметры ActionScript 3.0». Наконец, нажмите кнопку ОК, чтобы закрыть панель «Параметры публикации».

Теперь у вас есть две константы конфигурации, которые вы можете использовать, чтобы указать, какой код публикуется с вашим SWF. Давайте добавим эти две константы в ваш Applicationкласс. Добавьте строки кода, выделенные жирным шрифтом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public function Application()
{
    NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
    NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
    NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
     
    CONFIG::GEOLOCATION_SIMULATE
    {
        geolocation = new GeolocationSimulate();
    }
             
    CONFIG::GEOLOCATION_REAL
    {
        geolocation = new GeolocationReal();
    }
             
    geolocation.setRequestedUpdateInterval( 1000 );
    geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
}

Константы конфигурации могут быть установлены либо trueили false. Когда установлено значение true, любой код в блоке, определяемом константой, компилируется во время публикации. Если константе присвоено значение, falseто этот блок кода не компилируется.

Мы изначально настроены CONFIG::GEOLOCATION_SIMULATEна это trueозначает , что следующая строка кода в этом блоке будет компилируются:

1
2
3
4
CONFIG::GEOLOCATION_SIMULATE
{
    geolocation = new GeolocationSimulate();
}

Если мы устанавливаем , CONFIG::GEOLOCATION_SIMULATEчтобы falseи CONFIG::GEOLOCATION_REALв trueто строка кода в этом блоке будет компилируются вместо этого:

1
2
3
4
CONFIG::GEOLOCATION_REAL
{
    geolocation = new GeolocationReal();
}

Условная компиляция идеальна для включения и выключения блоков кода, которые, например, реализуют определенные специфичные для устройства функции или используются для отладки. Дополнительную информацию можно найти в этом кратком совете .

Сохраните изменения, которые вы внесли в Applicationкласс.


Всякий раз, когда вы хотите сделать сборку для своего устройства Android и хотите использовать GPS-модуль устройства, убедитесь, что вы изменили свои константы конфигурации следующим образом:

1
2
CONFIG::GEOLOCATION_REAL true
CONFIG::GEOLOCATION_SIMULATE false

Для тестирования на рабочем столе или на мобильном устройстве без необходимости полагаться на его устройство GPS, установите константы конфигурации на:

1
2
CONFIG::GEOLOCATION_REAL false
CONFIG::GEOLOCATION_SIMULATE true

Как вы можете себе представить, постоянное изменение этих значений на панели «Дополнительные параметры ActionScript 3.0» может быстро стать утомительным. Хорошей идеей является создание нескольких профилей публикации, каждый из которых имеет свои собственные параметры констант конфигурации.

В Flash CS5 выберите Файл | Параметры публикации …. Откроется панель «Параметры публикации».

Нажмите значок «Переименовать профиль» (четвертый значок справа от раскрывающегося списка «Текущий профиль») и назовите профиль «Реальный».

Нажмите кнопку ОК, чтобы выйти из панели «Свойства профиля» и зафиксировать имя профиля. Теперь перейдите на вкладку Flash на панели «Параметры публикации», затем нажмите кнопку « Настройки …» справа от параметра «Сценарий:». Перейдите на вкладку «Константы конфигурации» и убедитесь, что константы конфигурации указаны ниже:

Нажмите кнопку «ОК», чтобы закрыть панель «Дополнительные параметры ActionScript 3.0».

Теперь на панели «Параметры публикации» сделайте копию текущего профиля, щелкнув значок «Дублировать профиль» (третий значок справа от раскрывающегося списка «Текущий профиль»). Назовите дубликат профиля «Имитация».

Нажмите кнопку «ОК», чтобы выйти из панели «Дубликат профиля» и создать дубликат профиля.

Теперь на панели « Параметры публикации» нажмите кнопку « Настройки …» справа от параметра «Сценарий:». Нажмите на вкладку Константы конфигурации и измените константы конфигурации на значения, показанные ниже:

Нажмите кнопку «ОК», чтобы закрыть панель «Дополнительные параметры ActionScript 3.0». Нажмите кнопку ОК, чтобы закрыть панель «Параметры публикации».

Сохраните FLA.

Теперь у вас есть два профиля — Реальный и Имитация — которые вы можете легко переключать в зависимости от типа сборки, которую вы хотите создать при публикации. Это можно сделать довольно легко, выбрав File | Настройки публикации в Flash CS5. Теперь на панели «Параметры публикации» просто выберите нужный профиль в раскрывающемся списке «Текущий профиль»:

Попробуйте опубликовать профили как на рабочем столе, так и на устройстве Android.


Мы почти закончили к первой части этого урока, но давайте сделаем еще одну вещь, прежде чем закончить.

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

Так как же мы конвертируем метры в секунду в мили в час? Это не так сложно, чтобы быть честным. 1 метр в секунду равен 2.2369362920544 миль в час.

Прежде чем писать какой-либо код, добавьте к сцене текстовое поле, которое будет использоваться для отображения скорости в милях в час. Просто скопируйте существующие динамические и статические текстовые поля и расположите их непосредственно под существующими. Расположите дублированное динамическое текстовое поле в (10, 270) и поместите дубликат статического текстового поля в (95, 437).

Назовите дубликат экземпляра динамического текстового поля «milesPerHour». Измените текст внутри дублированного статического текстового поля на «миль в час».

Снимок ниже показывает, как ваша сцена должна выглядеть сейчас:

Добавьте в Applicationкласс общедоступную переменную-член, которая представляет новое динамическое текстовое поле:

1
2
3
public var metresPerSecond :TextField;
public var milesPerHour :TextField;
private var geolocation :IGeolocation;

Добавьте метод к вашему Applicationклассу, который выполняет преобразование. Вот код:

1
2
3
4
private function convertToMilesPerHour( metresPerSecond :Number ) :Number
{
    return metresPerSecond * CONVERSION_BASE;
}

Добавьте следующую константу в начало вашего класса:

1
static private const CONVERSION_BASE :Number = 2.2369362920544;

Наконец добавьте следующую строку кода в метод handleGeolocationUpdate ():

1
2
3
4
5
private function handleGeolocationUpdate( e :GeolocationEvent ) :void
{
    metresPerSecond.text = String( Math.round( e.speed ) );
    milesPerHour.text = String( Math.round( convertToMilesPerHour( e.speed ) ) );
}

Вы можете быть удивлены, почему я использую Math.round()для округления обоих значений скорости перед отображением их в текстовых полях. На самом деле это обходной путь для ошибки, обнаруженной мной во время выполнения AIR for Android, которая приводила к сбою моего Google Nexus One при отображении значений с плавающей запятой в текстовых полях.

Насколько я знаю, Adobe знает об этой ошибке, и она должна быть исправлена ​​в будущем выпуске.

Не стесняйтесь удалить Math.round()из handleGeolocationUpdate()метода и проверить его на вашем устройстве. Если это вызывает тот же сбой, который я испытал, то ваше устройство будет зависать на несколько минут перед перезагрузкой. Если вы довольны округлением значений, я бы посоветовал вам просто оставить код таким, какой он есть.

Сохранить класс.

Во избежание сомнений, вот текущая версия Applicationкласса в полном объеме:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package
{
    import flash.desktop.NativeApplication;
    import flash.desktop.SystemIdleMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.GeolocationEvent;
    import flash.events.KeyboardEvent;
    import flash.text.TextField;
    import flash.ui.Keyboard;
     
    public class Application extends Sprite
    {
        static private const CONVERSION_BASE :Number = 2.2369362920544;
         
        public var metresPerSecond :TextField;
        public var milesPerHour :TextField;
        private var geolocation :IGeolocation;
         
        public function Application()
        {
            NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
            NativeApplication.nativeApplication.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
            NativeApplication.nativeApplication.addEventListener( Event.DEACTIVATE, handleDeactivate );
             
            CONFIG::GEOLOCATION_SIMULATE
            {
                geolocation = new GeolocationSimulate();
            }
             
            CONFIG::GEOLOCATION_REAL
            {
                geolocation = new GeolocationReal();
            }
             
            geolocation.setRequestedUpdateInterval( 1000 );
            geolocation.addEventListener( GeolocationEvent.UPDATE, handleGeolocationUpdate );
        }
         
        private function handleGeolocationUpdate( e :GeolocationEvent ) :void
        {
            metresPerSecond.text = String( Math.round( e.speed ) );
            milesPerHour.text = String( Math.round( convertToMilesPerHour( e.speed ) ) );
        }
         
        private function handleKeyDown( e :KeyboardEvent ) :void
        {
            switch( e.keyCode )
            {
                case Keyboard.BACK:
                    NativeApplication.nativeApplication.exit();
                    break;
                 
                case Keyboard.SEARCH:
                case Keyboard.MENU:
                    e.preventDefault();
                    break;
            }
        }
         
        private function handleDeactivate( e :Event ) :void
        {
            NativeApplication.nativeApplication.exit();
        }
         
        private function convertToMilesPerHour( metresPerSecond :Number ) :Number
        {
            return metresPerSecond * CONVERSION_BASE;
        }
    }
}

Опубликуйте и запустите ваше приложение. Теперь вы должны увидеть скорость, измеряемую в метрах в секунду и в милях в час. Этот SWF должен показать вам, чего ожидать.

Если вы тестируете на своем рабочем столе, не забудьте выбрать профиль Simulate. Если вы проводите тестирование на устройстве Android с использованием профиля «Реал», не забудьте включить GPS-датчик телефона.


Первая часть этого урока охватила довольно много вопросов. Вы изучили основы разработки AIR для Android и потратили время на некоторые специфичные для AIR API, включая поддержку GPS и чтение из файловой системы. Кроме того, мы коснулись интерфейсов и узнали, как можно использовать условную компиляцию для включения и исключения кода из определенных сборок.

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

Спасибо за чтение и, надеюсь, еще увидимся во второй части на Activetuts + .


Иллюстрации, использованные в этом учебном пособии, были созданы с использованием шагов, описанных в разделе «Как создать иконку спидометра в Photoshop» — учебном пособии испанского гуру графического дизайна Роберто Абриль Идальго .

Огромное спасибо Дэйву Вагнеру за то, что он указал мне правильное направление со спецификой Mac OS X, необходимой для этого урока.

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