One of the most important things about any application, and especially mobile apps, is short start-up time. End user does not like to wait for too long for an app to start. In some cases, if the start-up time is excessively long a mobile app may not be accepted into an app store.
I have been building a lot of mobile apps recently for both Android and iOS in Delphi and found myself reusing the same “lazy form creation” design pattern, that I would like to share with you.
The idea is not new. Basically when your application starts, you only create the first form that is displayed, and all other forms are created when they are needed. Not earlier. This is especially important if your app is made of big number of different forms. Sometimes the app will be launched, forms created and never displayed.
The initial form (“splash screen”) should be as light as possible. It could for example contain a big logo and and a caption to “tap the screen to begin”.
In a simple case our mobile cross-platform Delphi project could contain just two forms: splash screen and the main screen. Start RAD Studio XE5 (or Delphi XE5) and create a new “FireMonkey Mobile Application – Delphi”. Save All. Save the form as “uFormSplash” and project as “LazyApp”. Click on the form and change its “Name” property in the Object Inspector to “FormSplash”. Now we are going to add to the project the second form, the main app screen, that is going to be created in a “lazy” fashion. Click on the “File” menu, “New” and “FireMonkey Mobile Form – Delphi”. This will add the second form to the project. Save All. Save the form as “uFormMain” and change its “Name” in the Object Inspector to “FormMain”. We have the starting point ready.
Let’s add code to display the second form. We can just drop the button on the splash screen, set its alignment property to “alClient”, change its “Text” property to “Welcome! Touch to begin!”.
Click on “File”, “Use Unit”, select “uFormMain” and “OK” in order to add “uFormMain” unit to “uses” clause of the “uFormSplash” unit.
Now double-click on the button on the form and in the generated “OnClick” event write a line of code to show the other form.
uses uFormMain;
procedure TFormSplash.Button1Click(Sender: TObject);
begin
FormMain.Show;
end</strong>;
Our application is now ready. We can click on “Run” green triangle button, in order build, deploy and launch the application on a mobile device of our choice: Android or iOS.
That’s a great start!
Click on the “Project” menu and select “View Source”. You should see the main program file of the app. This is the place where the execution of the app begins.
program LazyApp;
uses
System.StartUpCopy,
FMX.MobilePreview,
FMX.Forms,
uFormSplash in 'uFormSplash.pas' {FormSplash},
uFormMain in 'uFormMain.pas' {FormMain}</span>;
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TFormSplash, FormSplash);
Application.CreateForm(TFormMain, FormMain);
Application.Run;
end
Notice that before the “Application.Run” method is called, which basically starts the main application event loop – and the app starts to wait for user input – both forms of our application are created first. It would be faster to create just the splash form, that is going to be displayed first, and to create the second – main – form when it is needed. If we would have a big number of forms in our project that could significantly slow down our app start up time.
We can either just delete the line of code where “FormMain” is created or more elegantly we can go to the “Project” menu, select “Options” and then select “Forms” in the tree at the left side of the dialog. There are two lists of forms: those that are “auto created” and those that are just “available”. Click on the “FormMain” and move it to the list of available forms. Click on “OK”.
If we would run our application “as is” right now, we would get an error when trying to call the “Show” method on the “FormMain” object, because it does yet exist. Before we can call any of its methods, we need to create it and we just deleted the line of code that did this.
In most cases at this moment we would just write a line of code, just before the “FormMain.Show” method call, that creates the main form first. Our application would run again correctly. But this is not elegant approach.
Here comes the “Lazy Form Creation Design Pattern“!
Open the “uFormMain” unit in the editor . Move the global variable “var FormMain: TFormMain;” to the beginning of the “implementation” section of the unit. Change “FormMain” to “AFormMain”. Now we are going to define in the same place where our global variable was, a global function “function FormMain: TFormMain” that returns an instance of the TFormMain class. In this way we do not need to modify the code in any other unit that accesses any of the methods of the TFormMain class because the name of the function is the same as the name of the global variable was. The last task is to implement the function so it checks if the “AFormMain” variable is not “nil”, if it is “nil”, creates the form, and returns the resulting form.
unit uFormMain;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs;
type
TFormMain = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end</strong>;
function FormMain: TFormMain;
implementation
{$R *.fmx}
var
AFormMain: TFormMain;
function FormMain: TFormMain;
begin
if AFormMain = nil then
AFormMain := TFormMain.Create(Application);
Result := AFormMain;
end</strong>;
end.
I think this approach is elegant and I use it a lot in my projects. All forms are created in a lazy fashion and I do not need to worry in different places of my application logic if the form was already created or not.
I hope that you find this little thing useful!
Happy coding!