|
||||
|
Глава 4. Высокоуровневый программный интерфейс приложения (API) в MIDPНа данный момент вы знаете, как организовать пользовательский интерфейс базового приложения MIDP. В любом MID-лете, более сложном, чем первый приведенный для вас пример, вам придется определять множество экранов. Приложение передвигается от экрана к экрану, откликаясь на команды пользователя, вводимые с клавиатуры, экранных клавиш или функциональных кнопок обычного мобильного устройства. Чтобы создавать более сложные приложения, вам нужно изучить, как MIDP подгоняет вводимые пользователем данные и осуществляет обработку событий. В этой главе описывается высокоуровневый программный интерфейс приложения (API) MIDP, который определяет абстракции, подгоняемые к обработке высокоуровневых событий приложения. Высокоуровневый API является одним из двух API компонентов пользовательского интерфейса MIDP. Второй — это низкоуровневый API, о котором вы узнаете в главе 5. Термин высокоуровневый соответствует API верхнего уровня, который предоставляется программисту для работы в двух областях: — возможность манипулировать внешним видом и восприятием элементов («штучек») пользовательского интерфейса; — уровень разбиения информации о событиях и обработке событий. Все компоненты пользовательского интерфейса, принадлежащие иерархии класса Screen, реализуют высокоуровневый API. Эти элементы не дают вам возможность изменять их внешний вид и восприятие. Что же касается событий, информация, доступная приложению, является верхним уровнем абстракции. Приложения не имеют доступа к конкретным устройствам ввода. Например, используя абстракцию Screen, приложения не могут получить доступ к информации о том, какие физические клавиши нажимает пользователь. Высокоуровневый API разработан для коммерческих приложений, которые должны быть переносимыми на многочисленные устройства. Поэтому реализация MIDP удаляет все детали о таких вещах, как реализация на аппаратном обеспечении. Oбpaбoткa кoмaнд Высокоуровневый API MIDP поддерживает обработку событий с помощью использования команд. Команда представляет из себя действие пользователя — например, что-то, что пользователь делает на экране, к примеру, нажимает функциональную клавишу. Событие — это проявление результата действия. События могут представлять собой вызов команды в ответ на действие пользователя. Команда фиксирует семантическую информацию или отображение действия пользователя или события. Она не может, однако, определять поведение, которое вытекает из действия или события. Приложение определяет обработку — линию поведения, если хотите, — которая вытекает из появления некоторой команды. Класс Command в пакете javax.microedition.lcdui описывает команды. Этот класс инкапсулирует информацию о: — метке (label); — приоритетности (priority); — типе команды (command type). Метка — это String, подходящая для дисплея, с условием, что она может предоставлять пользователю семантику команды. Приоритетность является int, которая отражает важность команды по отношению к другим командам. Тип команды — это внутреннее представление намеченного использования команды. Текущая спецификация определяет типы команды, перечисленные в таблице 4.1. Таблица 4.1. Типы команд Константа типа команды — Описание
Сценарий oбработки команд Сценарий обработки команд в MIDP является теоретически сходным с другими ин-струментариями графического пользовательского интерфейса. Блок прослушивания команд (command listener) является объектом, который получает уведомления о наличии команд. Блоки прослушивания команд регистрируются для получения уведомления о командах. Некоторые внешние действия, такие, как нажатие пользователем на кнопку, отражаются в реализации MIDP, обнаруживая событие и связывая его с отображаемым в настоящее время экраном. Это инкапсулирует событие в объект Command. Зарегистрированный блок прослушивания команд получает уведомление о событии. Блок прослушивания затем предпринимает какое-либо действие, которое отражает поведение команды. Команды могут быть связаны только с элементами Displayable. To есть вы можете добавлять или удалять объекты Command в и из объекта Displayable с помощью следующих методов класса Displayable:
Объект блока прослушивания команд должен прикрепляться к Displayable для получения уведомления о команде с помощью вызова следующего метода в объекте
Только один блок прослушивания команд разрешен на один Displayable. Реализация MIDP поставляет команды только в текущий Displayable. Это ограничение пришлось ввести с учетом реалистичных ожиданий от производительности современных реализаций MIDP. MIDP определяет модель одной нити для обработки событий. Поддержка многочисленных блоков прослушивания команд потребовала бы модели со множеством нитей обработки событий. На рисунке 4.1 показана диаграмма UML связей между классами Displayable и Command и интерфейсом CommandListener. Рисунок 4.1. Эта диаграмма UML показывает связь между несколькими ключевыми классами, которые ответственны за создание, обнаружение и передачу командных событий вашему приложению Обратите внимание, что эта диаграмма не является всесторонним UML-представлением каждого представителя, атрибута типов и так далее. На рисунке 4.2 показана диаграмма экземпляра объекта, которая отражает взаимодействие экземпляров этих классов в работающем приложении. Рисунок 4.2. Эта диаграмма объекта показывает, что в работающем приложении могут существовать многие отображаемые на экране объекты и более чем один может регистрировать тот же самый блок прослушивания. Однако Displayable может иметь только один командный блок прослушивания В отличие от инструментария Swing MIDP не имеет общей модели блока прослушивания событий. Высокоуровневый API имеет только один тип командного блока прослушивания, называемого, что неудивительно, javax.microedition.lcdui.Command-Listener. В листинге 4.1 показана вторая версия MID-лета HelloWorld. Она добавляет экранные клавиши к главному окну и устанавливает блок прослушивания команд для распознавания нажатия пользователем на экранную клавишу. MID-лет отвечает, показывая другой вид экрана, называемый уведомлением (alert), который является MIDP-эквивалентом всплывающего диалогового окна. Листинг 4.1. В программу HelloWorld2 добавлена обработка команд
Вторая версия приложения HellcWorld. Эта версия добавляет команду в компонент Displayable и устанавливает
• блок прослушивания команд для активации команд и принятия какого-либо действия в ответ на нее. Этот пример демонстрирует, как Displayable определяет семантику выполнения команд.
Я создал вышеописанный МID-лет HelloWorld2 с помощью моего любимого текстового редактора. Затем я разместил исходный файл под управление установленного у меня инструментария Wireless Toolkit:
J2ME Wireless Toolkit компилирует все файлы. Java в директории. Компиляция проекта HelloWorld компилирует обе версии HelloWorld. На рисунке 4.3 показан стартовый экран эмулятора, который появляется, когда я открываю проект HelloWorld. Обратите внимание, что теперь вы видите два MID-лета в списке. Используя клавиши стрелок, выберите HelloWorld2 и запустите его, нажав экранную кнопку Launch (Запуск). На рисунке 4.4 показан главный экран HelloWorld2. Обратите внимание, что теперь справа появилась экранная клавиша под названием «Alert Me». На этом устройстве недостаточно места, чтобы показать полное сообщение «Alert Me!», которое установлено в исходном коде — так что восклицательный знак пропущен. Это первая проблема транспортабельности, с которой вы столкнулись, и она имеет практическое значение. К счастью, эмулятор поддерживает четыре различных устройства. Вы можете выполнить ваши MID-леты с помощью любого из четырех эмуляторов устройств, поддерживаемых эмулятором J2ME Wireless Toolkit Emulator, чтобы посмотреть, как они выглядят на каждом. Таким образом вы можете обнаружить множество потенциальных проблем, связанных с транспортабельностью. Рисунок 4.3. Добавление нового MID-лета к набору приводит в резул: тате к тому, что AMS отображает меню, из которого вы выбираете приложение, которое хотите запустить Рисунок 4.4. Основной экран MID-лета HelloWorld2 Ha рисунке 4.5 показан основной экран HelloWorld2, как он появляется при имитировании устройства Motorola i85s. Обратите внимание, что в отличие телефона со стандартными настройками, он способен отображать полный текст команды на экранной клавише. Есть также вторая Command с меткой «Say Hi», которая появляется на экранной клавише слева. Нажатие на экранную клавишу «Alert Me!» отображает экран уведомления, показанный на рисунке 4.6. Действие отображения этого экрана является поведением, которое HelloWorld2 определило для команды, связанной с выбором экранной клавиши. Взглянув на исходный код HelloWorld2, вы увидите, что, за исключением нескольких изменяющихся объявлений, логическая схема, которая формирует эту возможность обработки команд, находится в методе startApp(). Приложение создает экземпляр CommandListener. HelloWorld2 определяет внутренний класс, MyCommandListener, для выполнения обязанностей блока прослушивания команд. Он реализует интерфейс CommandListener. Вам не придется делать это таким способом. Вы можете, например, создать подкласс класса Form и заставить его реализовать CommandListener. Ваш подкласс является Form, который является разновидностью Screen, и поэтому он способен получать уведомления о вызове команды. Рисунок 4.5. Изображение первого экрана МID-лета HelloWorld2 с добавленной экранной клавишей на эмуляторе Motorola i85s Рисунок 4.6. Нажатие на экранную клавишу «Alert Me!» отображает это уведомление. Уведомления являются типом отображаемых экранов Определение CommandListener как интерфейса дает возможность использовать этот второй подход. Каждый тип Screen уже имеет класс более высокого уровня и поэтому не может наследовать от второго родительского класса. Использование интерфейсов Java особенно полезно в данном случае. После создания экземпляра MyCommandListener экземпляр регистрируется в Form. Затем приложение создает объект Command, чью метку заголовка «Alert Me!» вы видели в эмуляторе. Эта команда затем добавляется в форму. Когда пользователь нажимает экранную клавишу «Alert Me!» на работающем MID-лете, реализация «посылает» уведомление блоку прослушивания, экземпляру MyCommandListener, вызывая метод commandAction(). Метод commandAction () затем создает объект Alert и отображает его. Существует несколько важных теоретических моментов, связанных с этим примером. Обратите внимание, что я создал Command, но я не связал его с какой-либо определенной клавишей клавишной панели, кнопкой или экранной клавишей на устройстве. В действительности, при использовании высокоуровневого API ваше приложение не имеет способа получения информации о том, какая физическая клавиша нажата. Реализация присваивает Command специфическую клавишу — в этом случае экранную клавишу справа на дисплее устройства. Активизируйте экранную клавишу «Say Hi», расположенную слева в MID-лете HelloWorld2, и вы увидите, что в результате поведение будет тем же самым, как и если бы вы нажали кйопку «Alert Me!», появится то же самое уведомление. Конечно, это поведение неправильно, поскольку Alert показывает, что была активизирована клавиша «Alert Me!». Из-за абстракции высокоуровневого API, определяющего связи между ключами и командами, вы не можете присвоить блок прослушивания определенному ключу. Поскольку может быть больше одной команды на экран, вы должны использовать другую технику для того, чтобы дать возможность вашему блоку прослушивания команд идентифицировать источник команды и убедиться, что в ответ на события были выполнены нужные действия. Блок прослушивания регистрируется с и получает уведомления от Displayable, а не от источника события (такого, как клавиша кнопочной панели). Поэтому блок прослушивания должен идентифицировать и «выбрать» команду, в которой он заинтересован, среди всех возможных Command, связанных экраном, отображаемым в настоящее время. Вы, программист, должны убедиться, что вы должным образом связали поведение какого-либо блока прослушивания с должными Command. Вы должны использовать ин-. формацию, доступную в объекте Command, для ясной идентификации Command. Чтобы исправить ошибку в последней версии программы, я переписываю метод commandAction () в классе MyCommandListener, как показано в листинге 4.2. Листинг 4.2. Блок прослушивания команд теперь различает команды, исследуя их метки
Здесь все еще только один CommandListener на Screen — и может быть только один. Его метод commandAction () вызывается в ответ на нажатие любой клавиши. Но теперь он проверяет контекст уведомления объекта Command и выдает различные уведомления соответственно. Экранная навигация Пример HelloWorld2 демонстрирует центральную абстракцию MIDP — Screen. Вы, несомненно, уже обратили внимание, что. можете отображать одновременно только один Displayable — один Screen. Когда приложению необходимо отобразить Alert, ему приходится заменять основной экран. Причина этой одноэкранной абстракции кроется в ограниченности экранных ресурсов устройства. В отличие от инструментов графических пользовательских интерфейсов для настольных компьютеров, таких, как J2SE Swing toolkit, вы не можете иметь большое количество накладываемых друг на друга окон, всплывающих уведомлений, диалоговых окон и так далее. Хотя внедрение этих абстракций и не невозможно, требования памяти и ЦП на современных мобильных устройствах таковы, что фактически запрещают это. Более того, жидкокристаллические дисплеи с низким разрешением, низким потреблением энергии и маленькой площадью, характерные для большинства мобильных устройств, не приспособлены для этих абстракций. Даже дисплеи «карманных компьютеров» имеют минимально приемлемые характеристики для наложения окон, всплывающих окон и тому подобного. Однако очень вероятно, что примерно через год эти устройства будут иметь значительно большие мощности, порядка 50 МГц и 32 Мб RAM. Существует простая идиома экранной навигации, связанная с этой абстракцией экранов дисплея. Если вы хотите отобразить новый экран, просто установите, что экран является отображаемым в настоящий момент (current displayable). Чтобы сделать это, вы запрашиваете. объект Display вашего MID-лета на отображение Screen. Вспомните, в главе 2 вы узнали, что каждому MID-лету при запуске присваивается уникальный объект Display реализацией MIDP. Вы никогда не создаете объект Display, но вы можете получить ссылку на него, сделав следующий вызов со ссылкой на ваш MID-лет как на аргумент: Display.getDisplay(midlet); Затем вы просто делаете вызов метода, показанный далее, с аргументом, который ссылается на Displayable, который вы хотите отобразить:
Вы можете найти эти две строчки кода в методе startApp() обеих версий приложения HelloWorld. Разработка навигации и перемещений в вашем МЮ-лете включает следующие этапы: 1. Создание экранов. 2. Создание команд, которые вам нужны для каждого экрана. 3. Присвоение команд экранам. Для каждой команды каждого экрана определите следующий экран для отображения результата выполнения каждой команды. Важным атрибутом успешных приложений MIDP является легкая, интуитивная навигация между окнами. Анализ задач пользователя является темой отдельной книги и лежит за пределами темы данной книги. Самым важным, однако, является умение думать с точки зрения пользователя. Делайте все простым. Не путайте ваших пользователей, прыгая с места на место, так что пользователь не сможет следовать навигации. Слишком легко пользователю потеряться при просмотре на маленьком экране без контекстной привязки ко всему приложению. И никогда не создавайте ваши экраны, приспосабливая их к внутренней организации вашего приложения, его структуре данных, классам и так далее. Наоборот, позвольте дизайну вашего приложения следовать расположению, дизайну, навигации, последовательности экранов и так далее. Организация команд Взглянув более внимательно на пример, приведенный в предыдущем разделе, вы можете догадаться, что на самом деле вы не можете контролировать то, где появляется каждая из меток Command на экранных клавишах. Как-никак, я не указывал левую или правую экранную клавишу для размещения обеих Command. Приложение HelloWorld2 добавило клавиши «Alert Me!» и «Say Hi», в таком порядке. Первая появилась на правой экранной клавише, вторая — на левой. В действительности реализация управляет размещением меток Command на ваших отображаемых объектах Displayable в соответствии с некоторой политикой, зависящей от реализации. Вы можете познакомиться с различными политиками, просмотрев различные эмуляторы в беспроводном инструментарии. Вы сможете увидеть, что эмулятор Motorola размещает клавиши не так, как эмуляторы стандартных черно-белого и цветного телефонов. Следующая версия нашей программы HelloWorld, HelloWorldS, добавляет третью команду к главному экрану. Вместо того чтобы приводить вновь весь MID-лет целиком, я просто покажу части, которые отличаются от предыдущего примера. В масштабах класса HelloWorld3 определяет три объекта Command:
Третья версия приложения HelloWorld. Эта версия встраивается поверх HelloWorld2 с помощью добавления нескольких команд к компоненту Displayable. Здесь демонстрируется, что ComraandListener должен определять, какая из команд была активирована на экране. Вы также можете видеть, как реализация расставляет команды на экранных клавишах и как она создает меню и упорядочивает команды в меню в соответствии с типом команды.
В методе startApp() эти объекты Command добавляются к главному экрану следующим образом:
Создание и запуск этой новой версии в эмуляторе J2ME Wireless Toolkit Emulator отражен в главном экране, показанном на рисунке 4.7. Во-первых, обратите внимание, посмотрев на рисунок 4.7, что вы видите метку «Меню» на правой экранной клавише при запуске этого последнего MID-лета с помощью эмулятора стандартного черно-белого телефона. В программном коде определенно нигде нет определения меню. Рисунок 4.7. Реализация добавляет экранную клавишу «Меню», когда она обнаруживает более, двух команд, добавленных к текущему Displayable Устройства имеют только две экранные клавиши, но мы вставили три команды в наш главный экран. Реализация обнаружила это и создала меню, которое содержит вторую, третью и другие команды. На рисунке 4.8 показан дисплей после того, как вы выбрали клавишу «Меню». Запустите эту последнюю немодифицированную версию с помощью эмулятора Motorola iS5s, и вы увидите, что ключ «Меню» появится на левой экранной клавише, что отражено на рисунке 4.9. В действительности рисунки 4.8 и 4.9 демонстрируют, что конкретное поведение и политика размещения меню зависят от реализации. Рисунок 4.8. Выбор кнопки «Меню» отображает список элементов в экранном меню Рисунок 4.9. Размещение меток — команд- зависит от реализации Упорядочивание команд Вы, должно быть, удивлены, почему команда «Cancel» (Отмена) была помещена на экранную клавишу, даже несмотря на то, что бна была добавлена на экран последней. Интуитивно вы можете предположить, что она должна добавляться последней в меню. Вы бы предположили, конечно, что клавиша «Alert Me!», которая была добавлена первой, должна быть на экранной клавише. Объяснение этого очевидного отклонения заключается в том, что команды организуются в соответствии с их типом. Вспомните из предыдущего раздела этой главы, что одной из трех частей информации, которые определяют Command, является тип команды. Класс Command определяет константы, которые представляют собой действующие типы. Вы видели перечисление этих констант в таблице 4.1. Теперь я добавляю следующие объекты Command в пример HelloWorld3. На уровне классов я определяю следующие новые команды:
Обратите внимание, что каждая из команд имеет определенный тип. Эти различия дают вам возможность видеть, как реализация размещает команды на экране в соответствии с их типом. В методе startApp() я добавляю эти новые объекты команд к главному экрану. Новая версия startApp() выглядит таким образом:
Когда вы запустите новую версию, первое, что вы должны заметить, это то, что команда «Cancel» («Отмена») замещена командой «Exit» («Выход») на экранной клавише, как показано на рисунке 4.10. Активация меню показывает, что клавиша «Cancel» («Отмена») все еще на самом деле здесь, но теперь она в меню. Рисунок 4.10. Реализация MIDP определяет политику размещения команд в соответствии с их типом Размещение команд осуществляется в соответствии с их типом. Конкретная же политика, однако, зависит от реализации. Семантика команд Взгляните вновь на команду «Exit» («Выход»). Объект Command определяется с помощью метки «Exit» («Выход»). Но это не делает команду командой выхода! Я указал тип Command.EXIT в вызове конструктора. Это указание атрибута типа делает команду командой «Exit» («Выход»). Если бы я задал ее тип, как, скажем, Command. SCREEN, эта команда не появилась бы на экранной клавише. Вы можете попробовать проделать это самостоятельно. Реализация выбирает такую политику размещения команд, которая пытается максимально повысить удобство и простоту использования устройства. По-видимому, хорошей идеей является расположение клавиши «Exit» в легко доступном месте, поскольку это та клавиша, которая используется для навигации между окнами. Тем самым мы еще раз возвращаемся к мысли о том, что дружественная к пользователю навигация является наиболее важным моментом при работе на устройствах с маленькими экранами и более ограниченными механизмами пользовательского ввода. Наконец, несколько слов можно сказать о приоритетности команд. Обратите внимание, что организация команд, то есть размещение в соответствии с их типом, очень отличается от расстановки приоритетов поставки событий. Схема размещения ничего не делает с атрибутом приоритета Command, одним из трех атрибутов объектов Command. Приоритетность команд диктует приоритетность, которую реализация выдает командам при упорядочении их поставки в блок прослушивания. Я определил различные приоритеты для каждой команды в примере HelloWorldS. Вы можете убедиться, что приоритетность не влияет на размещение команд. Если вы немного поэкспериментируете с меню, вы сможете выяснить политику размещения команд реализации каждого устройства, предоставляемого эмулятором. Вы также можете изменить приоритетность команд в исходном коде и увидеть, как это влияет на_их размещение. В действительности расстановка приоритетов команд не является столь важной, когда вы работаете с высокоуровневыми API MIDP. Тем не менее, важно знать об этом понятии. Обычно пользователь не способен делать только одну вещь за раз, так что не будет лишним добавить высокоприоритетные события в приложение. Выводы по главе В этой главе вы узнали о высокоуровневом программном интерфейсе приложения (API) MIDP. Абстракции высокоуровневого API описывают следующее: — визуализация элементов пользовательского интерфейса; — обработка событий. MID-леты, которые используют высокоуровневый API, не могут изменять внешний вид и впечатление от элементов, И они не могут получать информацию о реальных клавишах устройства и нажимаемых кнопках, которые служат причиной активизации команды. Команды получают только семантическую информацию о «событии». Команда не представляет собой поведение или действие, которое осуществляется в ответ на событие. Блоки прослушивания команд задают поведение команд, определяя обработку, которая осуществляется в результате запуска команды реализацией. Определенная политика размещения меток команд на экране зависит от реализации. MIDP устанавливает, что размещение команд в меню должно быть сделано в соответствии с типом команды. Приоритетность команд диктуется порядком, в котором команды запускаются и посылаются в блок прослушивания команд. |
|
||
Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх | ||||
|