Understanding FireMonkey's Rendering Model

GPU-Accelerated UI and Scene Graph

FMX uses a GPU-backed scene graph rendering engine with support for 2D/3D transforms, effects, and animations. However, platform-specific GPU driver behavior can cause inconsistencies, particularly on Android devices with diverse hardware or on older iOS devices.

Multi-Platform Abstraction Layers

FireMonkey abstracts input, layout, and drawing, but certain behaviors (e.g., touch gestures, virtual keyboard, back-button handling) are not fully consistent across platforms, requiring conditional code using IFDEF or platform services.

Common Issues and Root Causes

1. Memory Leaks on Android/iOS

FMX controls and event handlers frequently leak due to improper ownership management. Anonymous threads or timers can hold references long after forms are destroyed.

// Leaky pattern
TTimer.Create(nil).OnTimer := procedure(Sender: TObject)
begin
  DoSomething; // Holds implicit references
end;

2. Black Screens or UI Flicker

Caused by GPU driver incompatibility or when FMX fails to correctly sync with the render thread. On Android, this often stems from missing RenderPolicy settings or lifecycle misalignment.

Application.RenderPolicy := TRenderPolicy.WaitForFinish; // Improves GPU sync

3. Platform Service Lookup Failures

FMX relies on platform services for native behavior. If services are not registered properly (e.g., IFMXVirtualKeyboardService), app behavior becomes unpredictable, especially on iOS where keyboard resizing is critical.

4. Inconsistent Form Behavior on Rotation

On Android/iOS, orientation changes sometimes cause form recreation or visual glitches. This is often due to improper use of OnResize vs OnOrientationChange.

Diagnostics and Debugging Techniques

Enable Memory Leak Reporting

Use ReportMemoryLeaksOnShutdown := True for Windows builds. For mobile, use RAD Studio's HeapTrc or external tools like Instruments (iOS) or LeakCanary (Android).

Log Platform Services

Dump service availability on startup to debug missing behavior.

var VKService: IFMXVirtualKeyboardService;
if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(VKService)) then
  Log('VK Service available')
else
  Log('VK Service missing');

Profile Render Thread

Use GPUFrameCapture (Android) or Xcode Instruments (iOS) to identify render bottlenecks in scenes with heavy effects, opacity animations, or blurred layers.

Use Conditional Breakpoints

Set breakpoints based on platform-specific conditions to isolate cross-platform bugs.

Fixes and Best Practices

Manage Timer and Thread Lifecycles Explicitly

Ensure all timers and threads are stopped and freed during FormClose or FormDestroy.

procedure TForm1.FormDestroy(Sender: TObject);
begin
  MyTimer.Enabled := False;
  MyTimer.Free;
end;

Use Platform-Specific Patches via IFDEF

Encapsulate per-platform logic to handle known inconsistencies.

{$IFDEF ANDROID}
DoAndroidFix;{$ENDIF}
{$IFDEF IOS}
DoIOSFix;{$ENDIF}

Handle Orientation Change Events Separately

Rely on OnOrientationChange for rotation-specific logic, not just form resizing.

Disable Unused Effects

Reduce GPU load by disabling heavy effects (e.g., blur, shadows) on mobile where they may not render consistently.

Enterprise Development Tips

  • Test on physical devices—not just simulators/emulators
  • Limit use of TCanvas.BeginScene where possible
  • Preload assets to avoid runtime file access lag on mobile
  • Use TFrame inheritance for modular, maintainable UIs
  • Integrate logging frameworks for cross-platform telemetry

Conclusion

Delphi FireMonkey is a powerful framework for building native cross-platform mobile applications, but it demands precise memory, rendering, and lifecycle management. Platform quirks, rendering policies, and service lookups can derail otherwise functional code without visible errors. By proactively applying diagnostics, isolating platform behavior, and embracing structured resource cleanup, developers can deliver smooth, consistent FMX experiences across all major mobile platforms.

FAQs

1. Why does my FMX app show a black screen on Android?

This is often due to GPU sync issues or unsupported effects. Set Application.RenderPolicy to WaitForFinish and remove unnecessary opacity/blur effects.

2. How do I avoid memory leaks in FireMonkey?

Explicitly free timers, forms, and anonymous methods that capture self-references. Use memory profiling tools where available.

3. Why is the virtual keyboard not resizing my layout?

The IFMXVirtualKeyboardService may be missing or incorrectly implemented. Verify service availability and adjust form behavior accordingly.

4. What is the best way to handle screen orientation changes?

Use OnOrientationChange rather than relying solely on resize events. Maintain separate layout states if needed.

5. Can I use FireMonkey for production iOS apps?

Yes, but you must rigorously test on real devices and conform to Apple's platform guidelines, including signing, sandboxing, and UI constraints.