Не прекращаю попыток в свободное от основной работы время разрабатывать небольшое приложение в Delphi для Android. Последнее, с чем пришлось столкнуться — работа с диалогами (InputQuery, InputBox, ShowMessage и тому подобное) при разработке для Android. Может я очень уж сильно отстал от последних нововведений в Delphi, а может эти нововведения и не нововведения вовсе (хотя документация Embarcadero свидетельствует об обратном), однако, в Delphi 10.1 Berlin большинство методов работы с диалогами были помечены как deprecated. И для работы с диалогами в FMX нам предлагается использовать вспомогательный класс TDialogService. Решил немного разобраться с тем, что это за зверь и какие сюрпризы в этом случае нам заготовлены при разработке приложений андроид в delphi.
Для начала, немного официальной документации. Что было помечено директивой deprecated и что предлагается использовать взамен:
Deprecated Members | New Members |
|
|
|
|
|
|
При этом методы ShowMessage и ShowMessageFmt, несмотря на их наличие в разделе deprecated members, не являются таковыми, однако нам рекомендуется использовать вместо них аналогичный синхронный или асинхронный вариант. Хорошо, посмотрим, как использовать нововведение.
Модуль FMX.DialogService
В этом модуле содержится всего один вспомогательный класс с несколькими классовыми методами, назначение которых, думаю, понятно по их названию:
TDialogService = class public type TPreferredMode = (Platform, Async, Sync); strict private class var FPreferredMode: TPreferredMode; class var FInSyncMode: Boolean; class procedure SetPreferredMode(const PreferredMode: TPreferredMode); static; public class constructor ClassCreate; class procedure ShowMessage(const AMessage: string); overload; class procedure ShowMessage(const AMessage: string; const ACloseDialogProc: TInputCloseDialogProc); overload; class procedure ShowMessage(const AMessage: string; const ACloseDialogEvent: TInputCloseDialogEvent; const AContext: TObject = nil); overload; class procedure MessageDialog(const AMessage: string; const ADialogType: TMsgDlgType; const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn; const AHelpCtx: LongInt; const ACloseDialogProc: TInputCloseDialogProc); overload; class procedure MessageDialog(const AMessage: string; const ADialogType: TMsgDlgType; const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn; const AHelpCtx: LongInt; const ACloseDialogEvent: TInputCloseDialogEvent; const AContext: TObject = nil); overload; class procedure InputQuery(const ACaption: string; const APrompts: array of string; const AValues: array of string; const ACloseQueryProc: TInputCloseQueryProc); overload; class procedure InputQuery(const ACaption: string; const APrompts: array of string; const AValues: array of string; const ACloseQueryEvent: TInputCloseQueryWithResultEvent; const AContext: TObject = nil); overload; class property PreferredMode: TPreferredMode read FPreferredMode write SetPreferredMode; end;
Использовать класс довольно просто. Например, мы хотим показать InputQuery. Вызываем соответствующий метод класса TDialogService:
TDialogservice.InputQuery('Введите что-нибудь', ['Ввод чего-нибудь'], [''], procedure(const AResult: TModalResult; const AValues: array of string) begin case AResult of mrOk: result:=AValues[0]; mrCancel: result:='Ввод чего-нибудь отменен'; end; end );
Свойство PreferredMode позволяет переключаться между синхронным и асинхронным режимами показа диалогов:
public type TPreferredMode = (Platform, Async, Sync);
По умолчанию свойство имеет значение Platform, то есть режим работы определяется операционной системой, однако нам не запрещается это свойство изменить при разработке под Android на Sync и тогда…
Синхронный или асинхронный InputQuery?
И когда я это сделал, то есть сменил значение свойства с Platform на Sync, тогда же и вспомнил старую, как мир заповедь: прежде, чем начинать использовать что-то — читай документацию. А в документации ясно и понятно сказано, что TDialogService использует в работе или IFMXDialogServiceSync или IFMXDialogServiceAsync (в зависимости от того, что мы попросим в свойстве PreferredMode). Поддержка этих интерфейсов в разных операционных системах следующая:
IFMXDialogServiceSync | IFMXDialogServiceAsync | |
Windows | ||
OS X | ||
iOS | ||
Android |
Как бы вы не старались и что бы вы не предпринимали в Android диалоги будут работать Асинхронно.
Что это значит для нас? Ну, например, при разработке под Android уже не получится написать, что-то наподобие вот такого:
if InputQuery('Введите пароль','Пароль',Value) then Password:=Value; //Тут что-то делаем с Password
Во-первых, потому, что теперь надо писать так:
TDialogservice.InputQuery('Введите пароль', ['Пароль'], [''], procedure(const AResult: TModalResult; const AValues: array of string) begin case AResult of mrOk: Password:=AValues[0]; mrCancel: Password:='Ввод пароля отменен'; end; end ); //Тут что-то делаем с Password
А во-вторых, так как вызов асинхронный, то программа не будет ждать пока пользователь нажмет на «Ok» или «Cancel», а сразу пойдет работать дальше. То есть сразу после показа диалога уйдет на строку
//Тут что-то делаем с Password
И это придётся каким-либо образом учитывать, если вы хотите разрабатывать приложения для андроид в delphi и использовать в этих приложениях InputQuery, InputBox и другие диалоги.
Кстати, про InputBox
Как вы могли заметить выше, в TDialogService нет реализации метода InputBox. Также его нет и в интерфейсах IFMXDialogServiceSync и IFMXDialogServiceAsync. Так что про использование этого диалога в FMX можно забыть и не вспоминать, а использовать вместо него InputQuery.
В общем-то, ничего особенно критичного не произошло, в связи с переходом на TDialogService для показа диалогов в Delphi 10.1, но, признаюсь, после долгого перерыва работы в этой области, пришлось немного пошерстить документацию в поисках ответа на вопрос «Почему в андроид InputBox работает не так, как я попросил (синхронно)?». А ответ-то, как оказалось, лежал на самом видном месте — в документации Emabrcedero. Всем удачных разработок в Delphi 10.1 для Android и до новых встреч на страницах блога webdelphi.ru ;)
Книжная полка