I am currently developing cross platform applications on my Windows desktop using Delphi XE-5. I have a unit I want to use for cross platform development (for this example, lets just work with Windows and Android).
In both my Windows and Android apps, I have a button with the following onClick event
procedure TfrmMain.Button1Click(Sender: TObject);
begin
LPSystem:= TLPSystem.Create;
try
if LPSystem.execute then
begin
ShowMessage('Logged in!');
end
else
ShowMessage('Not logged in!');
finally
LPSystem.Free;
end;
end;
In the execute routine below, a ShowModal dialog is displayed to the user ( a different form depending on platform)
function TLPSystem.execute: Boolean;
var
{$IFDEF MSWINDOWS}
frmLoginW: TfrmLoginW;
{$ENDIF MSWINDOWS}
{$IFDEF Android}
zResult: Boolean;
frmLoginM: TfrmLoginM;
{$ENDIF Android}
begin
result:= False;
{$IFDEF MSWINDOWS}
frmLoginW:= TfrmLoginW.Create(nil);
if frmLoginW.ShowModal = mrOK then
begin
{$ENDIF MSWINDOWS}
{$IFDEF Android}
frmLoginM:= TfrmLoginM.Create(nil);
frmLoginM.ShowModal (procedure(ModalResult: TModalResult)
begin
if ModalResult = mrOK then
begin
{$ENDIF Android}
{$IFDEF MSWINDOWS}
end;
frmLoginW.Free;
{$ENDIF MSWINDOWS}
{$IFDEF Android}
end;
end);
if zResult then result:= zResult;
frmLoginM.Free;
{$ENDIF Android}
end;
This works great for windows, but on Android, I get my result (i.e., the showmessage) before I get the modal dialog box. Not sure why?
Take away your IFDEF
statements and look at what you are actually doing:
Windows:
function TLPSystem.execute: Boolean;
var
frmLoginW: TfrmLoginW;
begin
Result := False;
frmLoginW := TfrmLoginW.Create(nil);
if frmLoginW.ShowModal = mrOK then
begin
end;
frmLoginW.Free;
end;
This is functionally OK (though it is not assigning the Result
based on the dialog's ModalResult
).
Android:
function TLPSystem.execute: Boolean;
var
zResult: Boolean;
frmLoginM: TfrmLoginM;
begin
Result := False;
frmLoginM := TfrmLoginM.Create(nil);
frmLoginM.ShowModal (
procedure(ModalResult: TModalResult)
begin
if ModalResult = mrOK then
begin
end;
end
);
if zResult then Result := zResult;
frmLoginM.Free;
end;
This is not following the rules outlined in Embarcadero's documentation:
ShowModal Dialogs in FireMonkey Mobile Apps
To make matters worse, the overloaded version of ShowModal()
that takes an anonymous procedure runs asynchronously, so your Execute()
would exit before the modal Form is closed. It cannot wait on the Form before exiting. So you will have to redesign your code to handle that.
Try something more like this:
type
TLPSystemLoginEvent = procedure(LoggedIn: Boolean) of object;
TLPSystem = class
private
procedure DoLoginResult(LoggedIn: Boolean);
public
OnLoginResult: TLPSystemLoginEvent;
procedure Execute;
end;
procedure TLPSystem.DoLoginResult(LoggedIn: Boolean);
begin
if Assigned(OnLoginResult) then OnLoginResult(LoggedIn);
end;
procedure TLPSystem.Execute;
var
{$IFDEF MSWINDOWS}
frmLoginW: TfrmLoginW;
{$ENDIF}
{$IFDEF Android}
frmLoginM: TfrmLoginM;
LSelf: TLPSystem;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
frmLoginW := TfrmLoginW.Create(nil);
try
DoLoginResult(frmLoginW.ShowModal = mrOK);
finally
frmLoginW.Free;
end;
{$ENDIF}
{$IFDEF Android}
frmLoginM := TfrmLoginM.Create(nil);
LSelf := Self;
frmLoginM.ShowModal(
procedure(ModalResult: TModalResult)
begin
LSelf.DoLoginResult(ModalResult = mrOK);
end
);
{$ENDIF}
end;
procedure TfrmLoginM.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
var
LPSystem: TLPSystem;
begin
LPSystem := TLPSystem.Create;
{$IFDEF MSWINDOWS}
try
{$ENDIF}
LPSystem.OnLoginResult := LoginResult;
LPSystem.Execute;
{$IFDEF MSWINDOWS}
finally
LPSystem.Free;
end;
{$ENDIF}
end;
procedure TfrmMain.LoginResult(LoggedIn: Boolean);
begin
if LoggedIn then
ShowMessage('Logged in!')
else
ShowMessage('Not logged in!');
end;
Alternatively, you can get rid of the try/finally
on Windows by utilizing an ARC interface
:
type
TLPSystemLoginEvent = procedure(LoggedIn: Boolean) of object;
ILPSystem = interface
procedure Execute;
end;
TLPSystem = class(TInterfacedObject, ILPSystem)
private
fOnLoginResult: TLPSystemLoginEvent;
procedure DoLoginResult(LoggedIn: Boolean);
public
constructor Create(ALoginResult: TLPSystemLoginEvent);
procedure Execute;
end;
constructor TLPSystem.Create(ALoginResult: TLPSystemLoginEvent);
begin
inherited Create;
fOnLoginResult := ALoginResult;
end;
procedure TLPSystem.DoLoginResult(LoggedIn: Boolean);
begin
if Assigned(fOnLoginResult) then fOnLoginResult(LoggedIn);
end;
procedure TLPSystem.Execute;
var
{$IFDEF MSWINDOWS}
frmLoginW: TfrmLoginW;
{$ENDIF}
{$IFDEF Android}
frmLoginM: TfrmLoginM;
LSelf: ILPSystem;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
frmLoginW := TfrmLoginW.Create(nil);
try
DoLoginResult(frmLoginW.ShowModal = mrOK);
finally
frmLoginW.Free;
end;
{$ENDIF}
{$IFDEF Android}
frmLoginM := TfrmLoginM.Create(nil);
LSelf := Self;
frmLoginM.ShowModal(
procedure(ModalResult: TModalResult)
begin
(LSelf as TLPSystem).DoLoginResult(ModalResult = mrOK);
end
);
{$ENDIF}
end;
procedure TfrmLoginM.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
var
LPSystem: ILPSystem;
begin
LPSystem := TLPSystem.Create(LoginResult);
LPSystem.Execute;
end;
procedure TfrmMain.LoginResult(LoggedIn: Boolean);
begin
if LoggedIn then
ShowMessage('Logged in!')
else
ShowMessage('Not logged in!');
end;