Разработка кроссплатформенных мобильных приложений в Delphi #3
Hастройка среды и создание нового мобильного приложения.
В предыдущей части цикла мы определились с задачей и создали простейшее FM приложение, которое отображает список рецептов. При этом мы использовали библиотеку доступа к данным FireDAC и технологию связывания объектов LiveBinding. Также мы условились, что в рамках поставленной задачи будет создано два приложения, использующих единую кодовую базу. И теперь, настало время для, возможно, самой интересной части – создания первого Android приложения.
Прежде всего, необходимо произвести настройку среды. Если при установке RAD Studio вы не устанавливали инструменты разработки Android (JDK/SDK/NDK), то вам следует сделать это вручную. Так же необходимо установить USB драйвер для того Android устройства, с помощью которого будет производиться разработка приложения. Стоит отметить, что далеко не для всех Android устройств можно найти USB драйвер. В таком случае можно воспользоваться возможностью отладки через Wi-Fi.
При создании нового проекта нам предлагается воспользоваться одним из нескольких шаблонов мобильного приложения. Выберем шаблон Header/Footer, представляющий собой мобильную форму с двумя панелями инструментов (Toolbar). После выбора шаблона необходимо сохранить проект. Новый проект удобнее всего создавать с помощью Project Manafer (правая верхняя панель IDE), как это показано на рисунке. Таким образом, мы сможем работать сразу с двумя проектами в группе.
Главная форма приложения для выбранного нами шаблона по умолчанию адаптирована под устройство Google Nexus 4. С помощью выпадающего списка в правой верхней части дизайнера формы можно выбрать другое устройство. Для нашего приложения выберем одно из наиболее популярных планшетных устройств Google Nexus 7. Сразу же изменим и текст заголовка на главной форме (свойство Text компонента HeaderLabel).
1 2 3 |
<span style="color: #000000; font-weight: bold;">implementation</span> <span style="color: #008000; font-style: italic;">{$R *.fmx}</span> <span style="color: #000000; font-weight: bold;">uses</span> uDM<span style="color: #000066;">;</span> |
Как вы уже поняли, для отладки приложения мы будем использовать физическое устройство, подключенное по USB. Хотя возможны и другие варианты (подключение с помощью Wi-Fi или использование эмулятора). Если вы подключили свой планшет или телефон в соответствии с инструкцией и активировали режим разработчика, то название вашего «девайса» появится в списке целевых устройств (Targets). Активируем его.
Еще раз убедитесь в том, что Android SDK настроен для вашего устройства, а т. н. «режим разработчика» активирован. Подробно весь процесс настройки среды для разработки Android приложения описан здесь.
Запускается мобильное приложение точно так же, как и обычное «настольное» (нажатием клавиши F9). Если вы все сделали правильно, то после компиляции вы увидите главную форму приложения на своем планшете.
Теперь попробуем реализовать тот же функционал, который мы реализовали в предыдущей части. Для этого добавим в текущий проект уже существующий модуль данных из предыдущего проекта (меню Project | Add to Project…). Как и в первом проекте, модуль надо включить в секцию Uses главной формы.
1 2 3 4 |
implementation {$R *.fmx} uses uDM; |
Собственно, теперь нам ничего не мешает использовать ту же процедуру установки соединения, которую мы использовали в «настольном» приложении:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span style="color: #000000; font-weight: bold;">function</span> TDM<span style="color: #000066;">.</span><span style="color: #006600;">ConnectToDB</span><span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">Boolean</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #000000; font-weight: bold;">try</span> FDConnection1<span style="color: #000066;">.</span><span style="color: #006600;">Connected</span> <span style="color: #000066;">:</span><span style="color: #000066;">=</span> <span style="color: #000000; font-weight: bold;">True</span><span style="color: #000066;">;</span> FDTRecipe<span style="color: #000066;">.</span><span style="color: #006600;">Open</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">except</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> Result<span style="color: #000066;">:</span><span style="color: #000066;">=</span> FDConnection1<span style="color: #000066;">.</span><span style="color: #006600;">Connected</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">procedure</span> TDM<span style="color: #000066;">.</span><span style="color: #006600;">DataModuleCreate</span><span style="color: #000066;">(</span>Sender<span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">TObject</span><span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> DM<span style="color: #000066;">.</span><span style="color: #006600;">ConnectToDB</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
Таким образом, мы избавили себя от необходимости повторно писать код установки соединения.
Главная форма приложения
В принципе, разработка пользовательского интерфейса мобильного приложения это отдельная, весьма обширная тема. Зачастую, именно неправильно спроектированный GUI может стать причиной неудачи. И иногда программисты пытаются перенести свой опыт создания интерфейсов «настольных» приложений на мобильную разработку. Это не совсем правильно. Перед тем, как приступить к написанию мобильного приложения стоит внимательно изучить базовые принципы дизайна интерфейсов. И, конечно же, стоит изучить интерфейсы популярных программ.
В нашем случае мы вполне можем организовать интерфейс главной формы мобильного приложения по образу «настольного» (на самом деле, интерфейс Windows приложения мы строили с учетом того, что нам придется делать мобильное приложение). Поместим на форму компоненты TPanel, TSplitter и TCalloutPanel. В Object Inspector поменяем их свойства следующим образом:
1 2 3 4 5 6 7 8 9 |
Panel1<span style="color: #000066;">:</span> TPanel Align <span style="color: #000066;">=</span> alLeft Splitter1<span style="color: #000066;">:</span> TSplitter Align <span style="color: #000066;">=</span> alLeft Width <span style="color: #000066;">=</span> <span style="color: #0000ff;">16</span> CalloutPanel1<span style="color: #000066;">:</span> TCalloutPanel Align <span style="color: #000066;">=</span> alClient Width <span style="color: #000066;">=</span> <span style="color: #0000ff;">630</span> TabOrder <span style="color: #000066;">=</span> <span style="color: #0000ff;">4</span> CalloutPosition <span style="color: #000066;">=</span> cpLeft |
Для отображения списка рецептов мы точно также используем TListBox и TBindNavigator, которые расположим на левой панели. TTabControl расположим на компоненте TCalloutPanel и настроим для каждого из компонентов свойство Align.
Как и в прошлый раз, используем механизм LiveBinding для подключения набора данных. Данная процедура полностью аналогична той, которую мы проделали в предыдущей части, создавая «настольное приложение».
Как и в прошлый раз, нам потребуется создать некий инструмент для ввода названия рецепта. Если в настольном приложении мы могли использовать модальную форму, то концепция мобильных приложений в большинстве случаев предлагает другое решение, более мягко регламентирующее действие пользователя. Однако здесь мы используем «диалог», который по сути можно расценивать как разновидность модальной формы.
Создадим новую мобильную форму. На ней поместим панель, и уже на панели разместим те элементы управления, которые мы размещали на форме добавления рецепта в прошлый раз (TEdit и две кнопки). Значение свойства Align – alCenter. Для кнопок зададим значение свойства ModalResult (mrOk и mrCancel).
Для класса формы создадим следующий метод класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000000; font-weight: bold;">procedure</span> TfAddRecipe<span style="color: #000066;">.</span><span style="color: #006600;">ShowDialog</span><span style="color: #000066;">(</span>DataSet<span style="color: #000066;">:</span> TDataSet<span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> fAddRecipe<span style="color: #000066;">.</span><span style="color: #006600;">ShowModal</span><span style="color: #000066;">(</span> <span style="color: #000000; font-weight: bold;">procedure</span><span style="color: #000066;">(</span>ModalResult<span style="color: #000066;">:</span> TModalResult<span style="color: #000066;">)</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #000000; font-weight: bold;">if</span> ModalResult<span style="color: #000066;">=</span> mrOk <span style="color: #000000; font-weight: bold;">then</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #000000; font-weight: bold;">if</span> DataSet<span style="color: #000066;">.</span><span style="color: #006600;">State</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000066;">[</span>dsInsert<span style="color: #000066;">,</span> dsEdit<span style="color: #000066;">]</span> <span style="color: #000000; font-weight: bold;">then</span> DataSet<span style="color: #000066;">.</span><span style="color: #006600;">Post</span><span style="color: #000066;">;</span> fAddRecipe<span style="color: #000066;">.</span><span style="color: #006600;">Close</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #000000; font-weight: bold;">if</span> DataSet<span style="color: #000066;">.</span><span style="color: #006600;">State</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000066;">[</span>dsInsert<span style="color: #000066;">,</span> dsEdit<span style="color: #000066;">]</span> <span style="color: #000000; font-weight: bold;">then</span> DataSet<span style="color: #000066;">.</span><span style="color: #006600;">Cancel</span><span style="color: #000066;">;</span> fAddRecipe<span style="color: #000066;">.</span><span style="color: #006600;">Close</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span> <span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
При запуске приложения назначим данный метод в качестве обработчика события AfterInsert для единственного пока набора данных в программе.
1 2 3 4 |
<span style="color: #000000; font-weight: bold;">procedure</span> THeaderFooterForm<span style="color: #000066;">.</span><span style="color: #006600;">FormShow</span><span style="color: #000066;">(</span>Sender<span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">TObject</span><span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> DM<span style="color: #000066;">.</span><span style="color: #006600;">FDTRecipe</span><span style="color: #000066;">.</span><span style="color: #006600;">AfterInsert</span><span style="color: #000066;">:</span><span style="color: #000066;">=</span> TfAddRecipe<span style="color: #000066;">.</span><span style="color: #006600;">ShowDialog</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
Данная форма будет вызываться при каждом добавлении записи в набор данных FDTRecipe.
Естественно, такой код нуждается в оптимизации. Создавать экземпляр формы при запуске приложения — не лучшая идея. Особенно для мобильных приложений. Но это тема для отдельного разговора, а пока из соображений наглядности оставим все как есть.
Развертывание (deployment) Android приложения
Перед тем, как запустить приложение, работающее с БД на Android, следует сделать определенные настройки, которые позволят перенести базу данных на мобильное устройство, и дадут возможность приложению «увидеть» базу. Для этого следует использовать Deployment Manager (меню Project |Deployment).
Убедитесь, что выбрана отладочная конфигурация для платформы Android. В выпадающем списке на верхней панели инструментов должно быть выбрано значение Debug configuration – Android platform.
Для того, что бы при развертывании приложения на устройство переносилась и база данных, следует воспользоваться кнопкой «Add files» (добавить файлы) и выбрать файл базы данных.
Введите assets\ в качестве значения поля Remote Path, а значение поля Platform установите Android. Директория assets это специальная директория, предназначенная для хранения вспомогательных ресурсов приложения. В поле Platform следует выбрать Android.
Вы можете нажать кнопку Deploy, что бы протестировать процесс развертывания приложения.
И, наконец, для того, что бы приложение заработало, следует сделать еще один важный шаг – определить событие компонента FDConnection1 следующим образом:
1 2 3 4 5 6 |
<span style="color: #000000; font-weight: bold;">procedure</span> TDM<span style="color: #000066;">.</span><span style="color: #006600;">FDConnection1BeforeConnect</span><span style="color: #000066;">(</span>Sender<span style="color: #000066;">:</span> <span style="color: #000066; font-weight: bold;">TObject</span><span style="color: #000066;">)</span><span style="color: #000066;">;</span> <span style="color: #000000; font-weight: bold;">begin</span> <span style="color: #008000; font-style: italic;">{$IFDEF ANDROID}</span> FDConnection1<span style="color: #000066;">.</span><span style="color: #006600;">Params</span><span style="color: #000066;">.</span><span style="color: #006600;">Values</span><span style="color: #000066;">[</span><span style="color: #ff0000;">'Database'</span><span style="color: #000066;">]</span> <span style="color: #000066;">:</span><span style="color: #000066;">=</span> <span style="color: #ff0000;">'$(DOC)/db.s3db'</span><span style="color: #000066;">;</span> <span style="color: #008000; font-style: italic;">{$ENDIF}</span> <span style="color: #000000; font-weight: bold;">end</span><span style="color: #000066;">;</span> |
Директива компилятора {$IFDEF ANDROID} передается для того, что бы данный код выполнялся только на Android устройствах. Таким образом, мы указываем приложению относительный путь к БД.
Запускаем приложение, и на экране устройства получаем практически полный аналог Windows приложения, которое мы создали в предыдущей части.
В этой части мы построили первое мобильное приложение и разобрались с тем, насколько процесс создания мобильных приложений в Delphi схож и насколько он отличается от процесса создания «обычного» desktop приложения. Естественно, пока мы реализовали только базовый функционал. Это касается как логики программы, так и ее интерфейса. Но, всему свое время. В следующей части мы продолжим работу над Windows приложением и более углубленно познакомимся с возможностями и принципами работы механизма LiveBinding.
Оставайтесь с нами.
Источник: habrahabr.ru