Mobile app lifecycle events handling in Delphi XE5

by Sep 30, 2013

Categories

Tags

Administration agent-based monitoring Agentless Monitoring alert responses alert thresholds alerting Alerts Amazon Aurora Amazon EC2 Amazon RDS Amazon RDS / Aurora Amazon RDS for SQL Server Amazon Redshift Amazon S3 Amazon Web Services (AWS) Analytics application monitoring Aqua Data Studio automation availability Azure Azure SQL Database azure sql managed instance Azure VM backup Backup and recovery backup and restore backup compression backup status Backup Strategy backups big data Blocking bug fixes business architecture business data objects business intelligence business process modeling business process models capacity planning change management cloud cloud database cloud database monitoring cloud infrastructure cloud migration cloud providers Cloud Readiness Cloud Services cloud storage cloud virtual machine cloud VM clusters code completion collaboration compliance compliance audit compliance audits compliance manager compliance reporting conference configuration connect to database cpu Cross Platform custom counters Custom Views customer survey customer testimonials Dark Theme dashboards data analysis Data Analytics data architect data architecture data breaches Data Collector data governance data lakes data lineage data management data model data modeler data modeling data models data privacy data protection data security data security measures data sources data visualization data warehouse database database administration database administrator database automation database backup database backups database capacity database changes database community database connection database design database developer database developers database development database diversity Database Engine Tuning Advisor database fragmentation database GUI database IDE database indexes database inventory management database locks database management database migration database monitoring database navigation database optimization database performance Database Permissions database platforms database profiling database queries database recovery database replication database restore database schema database security database support database synchronization database tools database transactions database tuning database-as-a-service databases DB Change Manager DB Optimizer DB PowerStudio DB2 DBA DBaaS DBArtisan dBase DBMS DDL Debugging defragmentation Demo diagnostic manager diagnostics dimensional modeling disaster recovery Download drills embedded database Encryption End-user Experience entity-relationship model ER/Studio ER/Studio Data Architect ER/Studio Enterprise Team Edition events execution plans free tools galera cluster GDPR Getting Started Git GitHub Google Cloud Hadoop Healthcare high availability HIPAA Hive hybrid clouds Hyper-V IDERA IDERA ACE Index Analyzer index optimization infrastructure as a service (IaaS) infrastructure monitoring installation Integrated Development Environment interbase Inventory Manager IT infrastructure Java JD Edwards JSON licensing load test load testing logical data model macOS macros managed cloud database managed cloud databases MariaDB memory memorystorage memoryusage metadata metric baselines metric thresholds Microsoft Azure Microsoft Azure SQL Database Microsoft PowerShell Microsoft SQL Server Microsoft Windows MongoDB monitoring Monitoring Tools Monyog multiple platforms MySQL news newsletter NoSQL Notifications odbc optimization Oracle PeopleSoft performance Performance Dashboards performance metrics performance monitoring performance schema performance tuning personally identifiable information physical data model Platform platform as a service (PaaS) PostgreSQL Precise Precise for Databases Precise for Oracle Precise for SQL Server Precise Management Database (PMDB) product updates Project Migration public clouds Query Analyzer query builder query monitor query optimization query performance Query Store query tool query tuning query-level waits Rapid SQL rdbms real time monitoring Real User Monitoring recovery regulations relational databases Releases Reporting Reports repository Restore reverse engineering Roadmap sample SAP Scalability Security Policy Security Practices server monitoring Server performance server-level waits Service Level Agreement SkySQL slow query SNMP snowflake source control SQL SQL Admin Toolset SQL CM SQL code SQL coding SQL Compliance Manager SQL Defrag Manager sql development SQL Diagnostic Manager SQL Diagnostic Manager for MySQL SQL Diagnostic Manager for SQL Server SQL Diagnostic Manager Pro SQL DM SQL Doctor SQL Enterprise Job Manager SQl IM SQL Inventory Manager SQL Management Suite SQL Monitoring SQL Performance SQL Quality SQL query SQL Query Tuner SQL Safe Backup SQL script SQL Secure SQL Security Suite SQL Server sql server alert SQL Server Migration SQL Server Performance SQL Server Recommendations SQL Server Security SQL statement history SQL tuning SQL Virtual Database sqlmemory sqlserver SQLyog Storage Storage Performance structured data Subversion Support tempdb tempdb data temporal data Tips and Tricks troubleshooting universal data models universal mapping unstructured data Uptime Infrastructure Monitor user experience user permissions Virtual Machine (VM) web services webinar What-if analysis WindowsPowerShell
The lifecycle of a mobile app is more complex and different from a desktop app. On a mobile device an application runs either in the foreground or in the background. When a phone calls arrive or when user opens another app, our app is going to background. If you are a programmer, you might be interested in responding to changes in the application state, for example saving current app state when your app goes into the background or refreshing the screen after moving into foreground.

Main two mobile operating systems, iOS and Android, fully support multitasking as their UNIX ancestor does. You would be surprised how many apps are constantly executing on your mobile device. On iOS just press the button below the screen twice, and a toolbar at the bottom of the screen will popup showing all executing apps. On Android devices you can also see all executing apps, but how you access the Task Manager may vary across devices. On my Nexus 7 tablet there is a special button next to "Home" button at the bottom of the screen to show the list of currently running apps.

The lifecycle of the application on Android is slightly different than on iOS. At the "developer" sections of web sites for both platforms you can find lifecycle charts. I have included them here for convenience.

Android app lifecycle is described at the http://developer.android.com/reference/android/app/Activity.html

iOS app lifecycle is described at the https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html

Delphi XE5 makes it possible use the same source code and just recompile your mobile app for Android or for iOS. There are differences in architecture of different services on different platforms. The FM Component Platform, also known as "FireMonkey", contains "FMX.Platform" unit, which provides common interfaces to services on different platforms. It also contains an interface definition of a "IFMXApplicationEventService" that makes it possible register an event handler to receive app lifecycle events.

type
TApplicationEvent = (aeFinishedLaunching, aeBecameActive, aeWillBecomeInactive,
aeEnteredBackground, aeWillBecomeForeground, aeWillTerminate, aeLowMemory,
aeTimeChange, aeOpenURL);

TApplicationEventHandler = function(AAppEvent: TApplicationEvent; AContext: TObject): Boolean of object
IFMXApplicationEventService = interface(IInterface)
['{F3AAF11A-1678-4CC6-A5BF-721A24A676FD}']
procedure SetApplicationEventHandler(AEventHandler: TApplicationEventHandler);
end

I just could not resist and decided to build a simple demo project to see what kinds of events my Delphi Mobile FireMonkey app would receive on different devices!

In your application code you need to define a function with the same signature as "TApplicationEventHandler". Basically it can be any function that takes "TApplicationEvent" and "TObject" parameters and returns "boolean".

Than you need to retrieve a reference to "IFMXApplicationEventService" from a global "TPlatformServices" class and register the app lifecycle event handler passing the reference to our event handler function as a parameter to "SetApplicationEventHandler" method of the service.

The "TPlatformServices" class contains "class" property called "Current" that returns the reference to "TPlatformServices" global, singleton implementation, so there is no need to instantiate it in our code.

Depending on the platform certain services may or may not be implemented, so you always need to check whether a given service is available. It is easy to use the following patterns to obtain references to different FireMonkey platform services. If the service is implemented in the "IFMXAService" interface, than we could use the following code snippet to access it:

 var aFMXAService: IFMXAService;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXAService, IInterface(aFMXAService)) then
begin
// call methods defined in the IFMXAService:
// aFMXAService.AMethod;
end
else
// FMXAService is not supported

Below is full code for a simple demo form that just registers the app lifecycle event handler and the handler itself displays the name of the lifecycle event and the time it was received in a memo component.

unit Unit11;

interface

uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
FMX.Memo, FMX.Platform, FMX.StdCtrls;

type
TForm11 = class(TForm)
Memo1: TMemo;
ToolBar1: TToolBar;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
procedure Log(s: string public
function HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
end
var
Form11: TForm11;

implementation

{$R *.fmx}

{ TForm11 }


procedure TForm11.FormCreate(Sender: TObject);
var aFMXApplicationEventService: IFMXApplicationEventService;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(aFMXApplicationEventService)) then
aFMXApplicationEventService.SetApplicationEventHandler(HandleAppEvent)
else
Log('Application Event Service is not supported.');
end
function TForm11.HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
begin
case AAppEvent of
aeFinishedLaunching: Log('Finished Launching');
aeBecameActive: Log('Became Active');
aeWillBecomeInactive: Log('Will Become Inactive');
aeEnteredBackground: Log('Entered Background');
aeWillBecomeForeground: Log('Will Become Foreground');
aeWillTerminate: Log('Will Terminate');
aeLowMemory: Log('Low Memory');
aeTimeChange: Log('Time Change');
aeOpenURL: Log('Open URL');
end Result := True;
end
procedure TForm11.Log(s: string begin
Memo1.Lines.Add(TimeToStr(Now) + ': ' + s);
end
end.

In the experiment I have compiled the application for "iOS Device" and "Android" targets. When the demo app started on the device, I have switched to another app and then back to the demo app.

In both cases the app has received "Became Active", "Entered Background" and "Will Become Foreground" events. On Android the demo app additionally received "Finished Launching" event at the beginning of the execution "Will Become Inactive" just before receiving "Entered Background".

Below there are screenshots from my iPhone 4S running iOS 6 and Nexus 2013 tablet running Android 4.3 running "LifecycleDemo" project.

The FM Component Framework ("FireMonkey") provides common abstractions for different functionality supported on different operating systems. In this way we do not need to maintain different code bases for working with different APIs! This also means hiding the underlying complexity of individual API from a programmer, so the application code can be simpler and more easy to understand and maintain!

There are more cool services to explore in the "FMX.Framework" unit! Give it a try:-)

The source code for the "LifecycleDemo" can be downloaded from Code Central.