< h2>Окружающая среда:
- Delphi 12.2 (последняя версия SP)
- APP для Android и iOS
- Аппаратное обеспечение Pixel 7a (Android 15) / Xiaomi Redmi (Android 12 SP1)
Проблема возникает только на устройствах Xiaomi (или, возможно, на устройствах других марок, которые я не тестировал). На Pixel он работает нормально.
В моем проекте я загружаю данные из конечной точки API в локальную базу данных SQLite. Затем я делаю фотографии и сохраняю их вместе с загруженными данными.
Вот проблемный код:
procedure TPhotoForm.TakePicture(Sender: TObject);
begin
if TOSVersion.Check(11) then
ActionTakePhotoFromCamera.Execute;
end;
Я использую тот же код, что и в примере с Embarcadero:
https://docwiki.embarcadero.com/CodeExa ... emo_Sample
Проблема возникает после вызова процедуры. Системная камера открывается, и я могу сделать снимок. Однако когда я выбираю изображение (чтобы вызвать событие OnFinishTakingPicture), приложение вылетает. Сообщения об ошибках нет — приложение просто перезапускается, как будто я запустил его снова.
И вот в чем особенность: это происходит не каждый раз. После нескольких повторов (3–4 попытки) или перезапуска приложения процесс фотосъемки работает нормально. Как только все заработает, оно продолжит работать, пока я не перезапущу приложение.
Чтобы последовательно воспроизвести проблему:
- Удалите приложение.
- Установите его заново.
- Сделайте фотографию при первом запуске.
В этом сценарии сбой происходит каждый раз. - li>
Что работает
Пример приложения от Embarcadero отлично работает на устройстве Xiaomi. Осознав это, я проверил несколько вещей:
Права доступа
Сначала я подумал, что это проблема. с правами доступа или манифестом Android. Я обновил все, чтобы соответствовать демо-проекту. Я также обнаружил, что вам на самом деле не нужны разрешения камеры при использовании системного диалога камеры. Интересно, но это не помогло — проблема все еще возникает.
Ошибка в FMX.MediaLibrary.Android
Затем я более подробно изучил код TAction.TakePhoto. Я отследил его до FMX.MediaLibrary.Android. Я исследовал два ключевых метода:
- TImageManagerAndroid.TakePhoto
- TImageManagerAndroid.TPhotoActivityResponseListener.onResponse
Метод onResponse вызывается каждый раз, когда диалоговое окно камеры закрывается, даже при сбое приложения. В случае сбоя приложения сначала запускается Application.Run, затем TPhotoActivityResponseListener.onResponse. Но когда приложение выходит из строя, LParams.OnDidFinishTaking недействителен, поскольку приложение перезапускается. Так что здесь все выглядит нормально — никаких очевидных проблем.
Управление энергопотреблением
Это похоже на какую-то проблему экономии заряда батареи. Возможно, Android пытается освободить ресурсы и закрывает мое приложение, пока камера открыта. Чтобы проверить это, я вручную установил APK и отключил всю оптимизацию батареи для своего приложения. Сбой все равно произошел.
**Редактировать: **
Оказывается, проблема связана с оптимизацией памяти Xiaomi. Каждый раз, когда использование ОЗУ приложения составляет около 150–450 МБ, система иногда приостанавливает приложение при открытии системной камеры (потому что мое приложение переходит в фоновый режим). Если объем оперативной памяти превышает 500 МБ, каждый раз происходит сбой. Я тестировал его даже с демо-приложением Embarcadero и смог воспроизвести ошибку.
Но я заметил, что, поскольку в стартовой форме в демо-приложении есть список действий, приложение может восстанавливаться даже при перезапуске, получая вызов события от OnFinishEvent. Есть идеи, как получить растровое изображение, если начальная форма не такая же, как та, которая изначально вызывала действие «Сфотографировать»? Вот код из FMX.MediaLibrary.Android. интересная часть — это то, что я использую TMessageManager.
try
LConverted := JBitmapToBitmap(LNativeBitmap, LBitmap);
LNativeBitmap.recycle;
if LConverted then
begin
if Assigned(LParams.OnDidFinishTaking) then
begin
log.d('OnDidFinishTaking is Assigned');
LParams.OnDidFinishTaking(LBitmap)
end
else
begin
log.d('OnDidFinishTaking is not Assigned');
LRequestKind := response.getRequestKind;
if LRequestKind.equals(TJPhotoActivityRequestKind.JavaClass.PICK) then
TMessageManager.DefaultManager.SendMessage(Self, TMessageDidFinishTakingImageFromLibrary.Create(LBitmap))
else if LRequestKind.equals(TJPhotoActivityRequestKind.JavaClass.TAKE) then
TMessageManager.DefaultManager.SendMessage(Self, TMessageDidFinishTakingImageFromCamera.Create(LBitmap));
end;
end;
finally
LBitmap.Free;
end;
Подробнее здесь: https://stackoverflow.com/questions/793 ... android-12