Это маленькая заметка о том, какие события происходят, когда мы запускаем приложение на Android. В ней я покажу логи из LogCat (с описанием тестов, которые провёл) и мы выясним, какие же события происходят всегда, а какие нет.
Ап. Добавил ссылку на пример, когда и как нужно сохранять данные приложения и объяснение, почему не видно событий в некоторых тестах.
Ап.2. Добавил данных по 4 тесту, добавил тест 8, изменил выводы :)
АП.3 (03.03.2017) Добавил табличку для визуализации результатов.
АП.4 (23.03.2017) Добавлена табличка для RAD Studio 10.2 Tokyo. Тесты проходили на Android 4.1.2; 4.4.2; 6.0.1.
Ап. Добавил ссылку на пример, когда и как нужно сохранять данные приложения и объяснение, почему не видно событий в некоторых тестах.
Ап.2. Добавил данных по 4 тесту, добавил тест 8, изменил выводы :)
АП.3 (03.03.2017) Добавил табличку для визуализации результатов.
АП.4 (23.03.2017) Добавлена табличка для RAD Studio 10.2 Tokyo. Тесты проходили на Android 4.1.2; 4.4.2; 6.0.1.
Наверняка многие читатели вспомнят, что я уже писал о жизненном цикле приложения в Android (это самая первая статья в блоге). В этот раз мы рассмотрим стандартные события приложения (onCreate, onPaint и т.д., полный список ниже) и события жизненного цикла.
Думаю, заметка пригодится многим, кто хочет корректно завершать работу функций в своём приложении.
Начнём сразу с кода, а потом перейдём к анализу полученных логов.
Набросал пустое приложение, в котором на каждом значимом событии повесил запись в LogCat.Думаю, заметка пригодится многим, кто хочет корректно завершать работу функций в своём приложении.
Начнём сразу с кода, а потом перейдём к анализу полученных логов.
Какие события будем мониторить:
- Стандартные: OnActivate, OnClose, OnCloseQuery, OnCreate, OnDeactivate, OnDestroy, OnFocusChanged, OnHide, OnPaint, OnResize, OnSavaState, OnShow.
- Android: События жизненного цикла (используем обновлённый код из предыдущей заметки - Справка)
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Platform; type TForm1 = class(TForm) procedure FormActivate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure FormCreate(Sender: TObject); procedure FormDeactivate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormFocusChanged(Sender: TObject); procedure FormHide(Sender: TObject); procedure FormPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF); procedure FormResize(Sender: TObject); procedure FormSaveState(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public { Public declarations } function HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.FormActivate(Sender: TObject); begin Log.d('FormActivate'); end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Log.d('FormClose'); end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin Log.d('FormCloseQuery'); end; procedure TForm1.FormCreate(Sender: TObject); var aFMXApplicationEventService: IFMXApplicationEventService; begin Log.d('FormCreate'); if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(aFMXApplicationEventService)) then aFMXApplicationEventService.SetApplicationEventHandler(HandleAppEvent) else Log.d('Application Event Service is not supported.'); end; procedure TForm1.FormDeactivate(Sender: TObject); begin Log.d('FormDeactivate'); end; procedure TForm1.FormDestroy(Sender: TObject); begin Log.d('FormDestroy'); end; procedure TForm1.FormFocusChanged(Sender: TObject); begin Log.d('FormFocusChanged'); end; procedure TForm1.FormHide(Sender: TObject); begin Log.d('FormHide'); end; procedure TForm1.FormPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF); begin Log.d('FormPaint'); end; procedure TForm1.FormResize(Sender: TObject); begin Log.d('FormResize'); end; procedure TForm1.FormSaveState(Sender: TObject); begin Log.d('FormSaveState'); end; procedure TForm1.FormShow(Sender: TObject); begin Log.d('FormShow'); end; function TForm1.HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; begin case AAppEvent of TApplicationEvent.FinishedLaunching: Log.d('Finished Launching'); TApplicationEvent.BecameActive: Log.d('Became Active'); TApplicationEvent.WillBecomeInactive: Log.d('Will Become Inactive'); TApplicationEvent.EnteredBackground: Log.d('Entered Background'); TApplicationEvent.WillBecomeForeground: Log.d('Will Become Foreground'); TApplicationEvent.WillTerminate: Log.d('Will Terminate'); TApplicationEvent.LowMemory: Log.d('Low Memory'); //aeTimeChange: Log('Time Change'); //not supported for Android //aeOpenURL: Log('Open URL'); //not supported for Android end; Result := True; end; end.
Компилим и устанавливаем на устройство.
Внимание! Логи основаны на тестах на LG L70 D-325 (Android 4.4.2) и Nexus 5 (Android 6.1), за тесты на Nexus 5 отдельное спасибо Равилю Зарипову, посетителю с форума Fire Monkey от А до Я
Результаты тестов (кроме №5) в таблице:
Переходим к тестам.
Тест 1:
- Запускаем приложение
- Выходим из приложения кнопкой «Back»
1) Запуск приложения
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormCreate
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormShow
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormActivate
09-20 20:13:43.161: I/info(15893): FMX: Project1: Finished Launching
09-20 20:13:43.221: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.231: I/info(15893): FMX: Project1: Became Active
09-20 20:13:43.261: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.281: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.311: I/info(15893): FMX: Project1: FormPaint
2) Выходим из приложения кнопкой «Back»
09-20 20:13:53.621: I/info(15893): FMX: Project1: FormCloseQuery
09-20 20:13:53.621: I/info(15893): FMX: Project1: FormClose
09-20 20:13:53.641: I/info(15893): FMX: Project1: FormSaveState
09-20 20:13:53.851: I/info(15893): FMX: Project1: Entered Background
09-20 20:13:53.871: I/info(15893): FMX: Project1: Will Become Inactive (в Android 6 – это событие происходит перед Entered Background)
09-20 20:13:54.421: I/info(15893): FMX: Project1: Will Terminate
09-20 20:13:54.671: I/info(15893): FMX: Project1: FormDeactivate
09-20 20:13:54.671: I/info(15893): FMX: Project1: FormDestroy
Как видим, все события отработали на ура, но не радуйтесь, это только первый тест…
Забегая вперёд, сразу скажу, что ниже не буду публиковать логи «Запуска приложения», т.к. они всегда одинаковы. Также я опустил все варнинги, которые вылезали при запуске.
Тест 2:
- Запускаем приложение
- Жмём кнопку «Home», тем самым возвращаясь на рабочий стол
- Зажимаем кнопку «Home» и жмём на наше приложение
- Запуск приложения – Логи как в первом тесте
- Жмём кнопку «Home», тем самым возвращаясь на рабочий стол
09-20 20:15:57.531: I/info(16159): FMX: Project1: Entered Background3. Зажимаем кнопку «Home» и жмём на наше приложение
09-20 20:15:57.651: I/info(16159): FMX: Project1: Will Become Inactive (в Android 6 – это событие происходит перед Entered Background)
09-20 20:15:58.041: I/info(16159): FMX: Project1: FormSaveState
09-20 20:16:11.591: I/info(16159): FMX: Project1: Will Become Foreground
09-20 20:16:11.701: I/info(16159): FMX: Project1: FormPaint
09-20 20:16:11.711: I/info(16159): FMX: Project1: Became Active
09-20 20:16:11.721: I/info(16159): FMX: Project1: FormPaint
09-20 20:16:11.731: I/info(16159): FMX: Project1: FormPaint
09-20 20:16:11.731: I/info(16159): FMX: Project1: FormPaint
Как видим, события FormCloseQuery, FormClose, Will Terminate, FormDeactivate, FormDestroy не происходят вообще.
Тест 3:
- Запускаем приложение (приложение находится на экране)
- Уничтожаем приложение через «список недавно запущенных приложений»
- Запускаем приложение (приложение находится на экране) – Логи как в первом тесте
- Закрываем приложение через «список недавно запущенных приложений»
09-20 20:19:05.771: I/info(16547): FMX: Project1: Entered Background
09-20 20:19:05.771: I/info(16547): FMX: Project1: Will Become Inactive(в Android 6 – это событие происходит перед Entered Background)
09-20 20:19:06.321: I/info(16547): FMX: Project1: FormSaveState
Как видим, события FormCloseQuery, FormClose, Will Terminate, FormDeactivate, FormDestroy не происходят вообще.
Тест 4:
- Запускаем приложение (приложение находится на экране)
- Даём устройству уснуть (экран гаснет, включается блокировка экрана) На моём устройстве: Экран гаснет через 30 секунд, блокировка через 5 секунд после экрана.
- Выждав немного времени, будим устройство
- Запускаем приложение (приложение находится на экране) – Логи как в первом тесте
- Даём устройству уснуть (экран гаснет, включается блокировка экрана) На моём устройстве: Экран гаснет через 30 секунд, блокировка через 5 секунд после экрана.
Android 4.4.2:3. Выждав немного времени, будим устройство
09-20 20:20:18.911: I/info(16867): FMX: Project1: Entered Background
09-20 20:20:18.961: I/info(16867): FMX: Project1: FormSaveState
09-20 20:20:25.061: I/info(16867): FMX: Project1: Will Become Inactive
09-21 20:40:08.250: I/info(18438): FMX: Project1: Will Become Foreground
09-21 20:40:08.370: I/info(18438): FMX: Project1: FormPaint
09-21 20:40:08.390: I/info(18438): FMX: Project1: Became Active
Тест 5:
- Устанавливаем галочку «Не сохранять действия» в «Опции разработчика»
- Запускаем приложение
- Сворачиваем кнопкой «Home»
- тут логов нет :)
- тут логи как в первом тесте
- Сворачиваем кнопкой «Home»
09-21 14:09:36.962: I/info(14135): FMX: Project1: Entered Background
09-21 14:09:37.582: I/info(14135): FMX: Project1: Will Become Inactive
09-21 14:09:37.962: I/info(14135): FMX: Project1: FormSaveState
09-21 14:09:37.992: I/info(14135): FMX: Project1: Will Terminate
09-21 14:09:38.242: I/info(14135): FMX: Project1: FormDeactivate
09-21 14:09:38.242: I/info(14135): FMX: Project1: FormDestroy
Запускаем приложениеСворачиваем кнопкокой «Home»Ждём, пока система сама убьёт приложение
АП
Если свернуть приложение, то потом мы уже не увидим события завершения приложения, т.к. система просто убивает процесс.
Пример из справки, когда сохранять данные приложения - FireMonkey Save State
АП.2.
Тест 8:
- Запускаем приложение
- Ждём пока экран выключится
- И сразу же включаем его обратно (экрана блокировки ещё не должно быть)
Первые два пункта совпадают с тестом 4 (первые два пункта)
3) 09-21 20:47:10.240: I/info(18907): FMX: Project1: Will Become Foreground
Общие выводы:
События, которые всегда(почти, смотри тест 8) происходят при старте (первый старт или восстановление через «Home»): Became Active (получение фокуса), Will Become Foreground и FormPaint.
События, которые всегда происходят при сворачивании или закрытии приложения: Entered Background (onPause), Will Become Inactive (потеря фокуса), FormSaveState.
Надеюсь, эта информация поможет вам правильно строить приложение.
Использовалась RAD Studio Berlin (include update 1)