• 0
Alisson R Oliveira

Firemonkey TTakePhotoFromCameraAction.OnDidFinishTaking causes my app to restart

Вопросы

привет привет
у кого-то были проблемы с «TTakePhotoFromCameraAction» и «TTakePhotoFromLibraryAction» TActions, они используют их как источник входных данных для изображений в приложении. он обычно загружается вскоре после того, как пользователь подтвердит изображение, приложение и перезапустится. Думаю, он думает до или после входа в мероприятие «OnDidFinishTaking».

Кто-нибудь знает, как это исправить? Я использую Берлин.

благодарный

 

Hello,
someone has had problems with the "TTakePhotoFromCameraAction" and "TTakePhotoFromLibraryAction" TActions, they use them as an input source for images in the app. it usually loads soon after the user confirms the image, the app and restarted I believe he thinks before or upon entering the event "OnDidFinishTaking".

Does anyone know how to fix it? I'm using Berlin.

thankful

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 ответов на этот вопрос

  • 0

Embarcadero wiki: http://docwiki.embarcadero.com/Libraries/Berlin/en/FMX.MediaLibrary.TMessageDidFinishTakingImageFromLibrary

Цитата

TMessageDidFinishTakingImageFromLibrary messages are only sent if the call to IFMXTakenImageService.TakeImageFromLibrary does not specify an event handler for successfully taking a picture. However, even if you do specify this event handler, Android may unload your application while your user is selecting a picture. When your application regains focus, it might actually have restarted, and any event information passed on the call to IFMXTakenImageService.TakeImageFromLibrary is lost, which is why a TMessageDidFinishTakingImageFromLibrary message is sent instead

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 15/08/2018 в 05:01, Tumaso сказал:

Извините, документация Embarcadero для меня немного запутанна. Если я правильно понимаю, предлагает ли я создать ПРОЦЕДУРУ и назначить ее во время выполнения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Пример моего кода:

interface 

type
  TMyForm = class(TForm)
    { ... }
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    {$IFDEF ANDROID}
    procedure ImageFileMessageListener(const Sender: TObject; const M: TMessage);
    {$ENDIF}
    {$IFDEF IOS}
    procedure ImageFileFinish(Image: TBitmap);
    {$ENDIF}
    procedure ImageFromLibraryClick(Sender: TObject);
    { ... }
  private
    { ... }
    procedure ApplyImage(Image: TBitmap);
    { ... }
  end;

implementation

procedure TMyForm.FormCreate(Sender: TObject);
begin
{$IF DEFINED(ANDROID)}
  TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromLibrary, ImageFileMessageListener);
{$ENDIF} 
end;

procedure TMyForm.FormDestroy(Sender: TObject);
begin
{$IF DEFINED(ANDROID)}
  TMessageManager.DefaultManager.Unsubscribe(TMessageDidFinishTakingImageFromLibrary, ImageFileMessageListener, True);
{$ENDIF} 
end;

{$IFDEF ANDROID}

procedure TMyForm.ImageFileMessageListener(const Sender: TObject; const M: TMessage);
begin
  try
    if M is TMessageDidFinishTakingImageFromLibrary then
      ApplyImage(TMessageDidFinishTakingImageFromLibrary(M).Value);
  except
    { code for exception handle }
  end;
end;

{$ENDIF}

{$IFDEF IOS}

procedure TMyForm.ImageFileFinish(Image: TBitmap);
begin
  try
    ApplyImage(Image);
  except
    { code for exception handle }
  end;
end;

{$ENDIF}

procedure TMyForm.ImageFromLibraryClick(Sender: TObject);
{$IF DEFINED(ANDROID) OR DEFINED(IOS)}
var
  LImageService: IFMXTakenImageService;
  LImageParams: TParamsPhotoQuery;
{$ENDIF}
begin
  if TPlatformServices.Current.SupportsPlatformService(IFMXTakenImageService, IInterface(LImageService)) then
  begin
    LImageParams.RequiredResolution := TSize.Create(1024, 1024);
    LImageParams.Editable := False;
    LImageParams.NeedSaveToAlbum := False;
    // под Android обработчик OnDidFinishTaking указывать нельзя, т.к. это может привести к рестарту программы
    // см. http://docwiki.embarcadero.com/Libraries/Berlin/en/FMX.MediaLibrary.TMessageDidFinishTakingImageFromLibrary
    LImageParams.OnDidFinishTaking := {$IFDEF IOS}ImageFileFinish{$ELSE}nil{$ENDIF};
    LImageParams.OnDidCancelTaking := nil;
    LImageService.TakeImageFromLibrary({$IFDEF IOS}ImageFile{$ELSE}nil{$ENDIF}, LImageParams);
  end
  else
    raise Exception.Create('No image library access');
end;

procedure TMyForm.ApplyImage(Image: TBitmap);
begin
  { code for received image }
end;

 

Изменено пользователем Tumaso

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
4 часа назад, Tumaso сказал:

Пример моего кода:


interface 

type
  TMyForm = class(TForm)
    { ... }
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    {$IFDEF ANDROID}
    procedure ImageFileMessageListener(const Sender: TObject; const M: TMessage);
    {$ENDIF}
    {$IFDEF IOS}
    procedure ImageFileFinish(Image: TBitmap);
    {$ENDIF}
    procedure ImageFromLibraryClick(Sender: TObject);
    { ... }
  private
    { ... }
    procedure ApplyImage(Image: TBitmap);
    { ... }
  end;

implementation

procedure TMyForm.FormCreate(Sender: TObject);
begin
{$IF DEFINED(ANDROID)}
  TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromLibrary, ImageFileMessageListener);
{$ENDIF} 
end;

procedure TMyForm.FormDestroy(Sender: TObject);
begin
{$IF DEFINED(ANDROID)}
  TMessageManager.DefaultManager.Unsubscribe(TMessageDidFinishTakingImageFromLibrary, ImageFileMessageListener, True);
{$ENDIF} 
end;

{$IFDEF ANDROID}

procedure TMyForm.ImageFileMessageListener(const Sender: TObject; const M: TMessage);
begin
  try
    if M is TMessageDidFinishTakingImageFromLibrary then
      ApplyImage(TMessageDidFinishTakingImageFromLibrary(M).Value);
  except
    { code for exception handle }
  end;
end;

{$ENDIF}

{$IFDEF IOS}

procedure TMyForm.ImageFileFinish(Image: TBitmap);
begin
  try
    ApplyImage(Image);
  except
    { code for exception handle }
  end;
end;

{$ENDIF}

procedure TMyForm.ImageFromLibraryClick(Sender: TObject);
{$IF DEFINED(ANDROID) OR DEFINED(IOS)}
var
  LImageService: IFMXTakenImageService;
  LImageParams: TParamsPhotoQuery;
{$ENDIF}
begin
  if TPlatformServices.Current.SupportsPlatformService(IFMXTakenImageService, IInterface(LImageService)) then
  begin
    LImageParams.RequiredResolution := TSize.Create(1024, 1024);
    LImageParams.Editable := False;
    LImageParams.NeedSaveToAlbum := False;
    // под Android обработчик OnDidFinishTaking указывать нельзя, т.к. это может привести к рестарту программы
    // см. http://docwiki.embarcadero.com/Libraries/Berlin/en/FMX.MediaLibrary.TMessageDidFinishTakingImageFromLibrary
    LImageParams.OnDidFinishTaking := {$IFDEF IOS}ImageFileFinish{$ELSE}nil{$ENDIF};
    LImageParams.OnDidCancelTaking := nil;
    LImageService.TakeImageFromLibrary({$IFDEF IOS}ImageFile{$ELSE}nil{$ENDIF}, LImageParams);
  end
  else
    raise Exception.Create('No image library access');
end;

procedure TMyForm.ApplyImage(Image: TBitmap);
begin
  { code for received image }
end;

 

Большое спасибо ... Это очень помогло! Вскоре после прочтения вашего поста я углубился в документацию Embarcadero и нашел этот пример http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Taking_Pictures_Using_FireMonkey_Interfaces (если кому захочется).

Посмотрите, можете ли вы мне помочь.
Представьте, что в Tform у меня есть 5 разных TImage, где он получает разные изображения, поступающие из библиотек, как работать, поскольку он ссылается только на один объект, чтобы получить TImage

procedure TMyForm.ImageFileMessageListener(const Sender: TObject; const M: TMessage);
begin
  try
    if M is TMessageDidFinishTakingImageFromLibrary then
      ApplyImage(TMessageDidFinishTakingImageFromLibrary(M).Value);
  except
    { code for exception handle }
  end;
end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Android/iOS не даст запустить одновременно 2 и более диалогов выбора изображений из библиотеки. Поэтому задача тривиальна - перед вызовом TakeImageFromLibrary запоминаешь TImage (любым способом), в которое нужно будет занести изображение. А в ApplyImage по сохраненному значению определяешь, в какой TImage заносить.

По получению изображения из камеры - тут нужно использовать TCameraComponent (работает стабильно).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
27 минут назад, Tumaso сказал:

O Android / iOS não permitirá que você execute 2 ou mais caixas de diálogo de seleção de imagens da biblioteca ao mesmo tempo. Portanto, a tarefa é trivial - antes de chamar TakeImageFromLibrary, lembre-se de TImage (de qualquer forma), em que você precisará colocar a imagem. E em ApplyImage no valor salvo você determina em qual TImage para entrar.

 Ao receber a imagem da câmera - aqui você precisa usar o TCameraComponent (ele funciona de forma estável).

Может быть, это будет немного более конкретным? Я все еще получаю сообщение об ошибке, и приложение перезапустилось

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Work with camera:

interface

type
  TMyForm = class(TForm)
    { ... }
    Image1: TImage;
    Image2: TImage;
    Camera1: TCameraComponent;
    Camera2: TCameraComponent;
    RectangleCamera1On: TRectangle;
    RectangleCamera1Off: TRectangle;
    RectangleCamera2On: TRectangle;
    RectangleCamera2Off: TRectangle;
    { ... }
    procedure FormCreate(Sender: TObject);
    { ... }
    procedure Camera1SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
    procedure Camera2SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
    procedure Camera1OnClick(Sender: TObject);
    procedure Camera1OffClick(Sender: TObject);
    procedure Camera2OnClick(Sender: TObject);
    procedure Camera2OffClick(Sender: TObject);
    { ... }
  private
    { ... }
    procedure RetrieveCamera1Image;
    procedure RetrieveCamera2Image;
    { ... }
  end;

implementation

procedure TMyForm.FormCreate(Sender: TObject);
begin
  RectangleCamera1On.OnClick := Camera1OnClick;
  RectangleCamera1Off.OnClick := Camera1OffClick;
  RectangleCamera2On.OnClick := Camera2OnClick;
  RectangleCamera2Off.OnClick := Camera2OffClick;
  Camera1.OnSampleBufferReady := Camera1SampleBufferReady;
  Camera1.Kind := TCameraKind.FrontCamera;
  Camera2.OnSampleBufferReady := Camera2SampleBufferReady;
  Camera2.Kind := TCameraKind.BackCamera;
end;

procedure TMyForm.Camera1SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
begin
  TThread.Synchronize(TThread.CurrentThread, RetrieveCamera1Image);
end;

procedure TMyForm.Camera2SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
begin
  TThread.Synchronize(TThread.CurrentThread, RetrieveCamera2Image);
end;

procedure TMyForm.Camera1OnClick(Sender: TObject);
begin
  Camera1.Active := True;
end;

procedure TMyForm.Camera1OffClick(Sender: TObject);
begin
  Camera1.Active := False;
end;

procedure TMyForm.Camera2OnClick(Sender: TObject);
begin
  Camera2.Active := True;
end;

procedure TMyForm.Camera2OffClick(Sender: TObject);
begin
  Camera2.Active := False;
end;

procedure TMyForm.RetrieveCamera1Image;
var
  LBitmap: TBitmap;
  LScaleXY: Double;
  LScale: Double;
  LWidth: Double;
  LSource: TRectF;
begin
  if Image1.Height > 0 then
    LScaleXY := Image1.Width / Image1.Height
  else  
    LScaleXY := 1;
  try
    LBitmap := TBitmap.Create;
    try
      Camera1.SampleBufferToBitmap(LBitmap, True);
      if (LBitmap.Width > 0) and (LBitmap.Height > 0) then
      begin
        LScale := LBitmap.BitmapScale / Image1.Bitmap.BitmapScale;
        LWidth := LBitmap.Height * LScaleXY;
        LSource := TRectF.Create((LBitmap.Width - LWidth) / 2, 0, LWidth + (LBitmap.Width - LWidth) / 2, LBitmap.Height);
        with Image1.Bitmap do
        begin
          SetSize(Round(Image1.Width), Round(Image1.Height));
          if Canvas.BeginScene then
          begin
            try
              Canvas.DrawBitmap(
                LBitmap,
                Canvas.AlignToPixel(LSource),
                Canvas.AlignToPixel(TRectF.Create(0, 0, Width * LScale, Height * LScale)),
                1,
                False
                );
            finally
              Canvas.EndScene;
            end;
          end;
        end;
      end;
    finally
      LBitmap.DisposeOf;
    end;
  except
    { some code }
  end;
end;

procedure TMyForm.RetrieveCamera2Image;
var
  LBitmap: TBitmap;
  LScaleXY: Double;
  LScale: Double;
  LWidth: Double;
  LSource: TRectF;
begin
  if Image2.Height > 0 then
    LScaleXY := Image2.Width / Image2.Height
  else  
    LScaleXY := 1;
  try
    LBitmap := TBitmap.Create;
    try
      Camera2.SampleBufferToBitmap(LBitmap, True);
      if (LBitmap.Width > 0) and (LBitmap.Height > 0) then
      begin
        LScale := LBitmap.BitmapScale / Image2.Bitmap.BitmapScale;
        LWidth := LBitmap.Height * LScaleXY;
        LSource := TRectF.Create((LBitmap.Width - LWidth) / 2, 0, LWidth + (LBitmap.Width - LWidth) / 2, LBitmap.Height);
        with Image2.Bitmap do
        begin
          SetSize(Round(Image2.Width), Round(Image2.Height));
          if Canvas.BeginScene then
          begin
            try
              Canvas.DrawBitmap(
                LBitmap,
                Canvas.AlignToPixel(LSource),
                Canvas.AlignToPixel(TRectF.Create(0, 0, Width * LScale, Height * LScale)),
                1,
                False
                );
            finally
              Canvas.EndScene;
            end;
          end;
        end;
      end;
    finally
      LBitmap.DisposeOf;
    end;
  except
    { some code }
  end;
end;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я получаю ошибку при выборе образа библиотеки.

Я отправлю свой код

Uses

  //Imagens 
  FMX.MediaLibrary, FMX.platform, System.Messaging;

 

type

TfrmUsuario = class(TForm)

{...}

    procedure DoMessageListener(const Sender: TObject; const M: TMessage);

private

    procedure AplicarFoto(Image: TBitmap);

 

procedure TfrmUsuario.FormCreate(Sender: TObject);
var
  dmControllerUsuario: TdmControllerUsuario;
begin

  if not Assigned(dmControllerUsuario) then
    dmControllerUsuario := TdmControllerUsuario.Create(nil);


  TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromLibrary, DoMessageListener);

end;

procedure TfrmUsuario.FormDestroy(Sender: TObject);
begin
  TMessageManager.DefaultManager.Unsubscribe(TMessageDidFinishTakingImageFromLibrary, DoMessageListener, True);
end;
 

procedure TfrmUsuario.actGaleriaRunExecute(Sender: TObject);
var
  LImageService: IFMXTakenImageService;
  LImageParams: TParamsPhotoQuery;
begin

  if TPlatformServices.Current.SupportsPlatformService(IFMXTakenImageService, IInterface(LImageService)) then
  begin
    LImageParams.RequiredResolution := TSize.Create(1024, 1024);
    LImageParams.Editable := False;
    LImageParams.NeedSaveToAlbum := False;
    LImageParams.OnDidFinishTaking := nil;
    LImageParams.OnDidCancelTaking := nil;
    LImageService.TakeImageFromLibrary(nil, LImageParams);
  end
  else
    ShowMessage('This device does not support the camera service');

end;

procedure TfrmUsuario.DoMessageListener(const Sender: TObject; const M: TMessage);
begin

  try
    if M is TMessageDidFinishTakingImageFromLibrary then
      AplicarFoto(TMessageDidFinishTakingImageFromLibrary(M).Value);
  except

  end;

end;

 

procedure TfrmUsuario.AplicarFoto(Image: TBitmap);
begin

  circleFoto.Fill.Bitmap.Bitmap.Assign(Image);

end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я заметил, что, позволяя редактировать изображение, проблема становится еще хуже.

LImageParams.Editable := True;

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Alisson R Oliveira,

required permissions for TakeImageFromLibrary: READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE. I use TakeImageFromLibrary only on android 5+, because on android 4.x application with TakeImageFromLibrary may crash any time.

required permission for TakePhotoFromcamera and TCameraComponent: CAMERA

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Все разрешения в порядке ... Какова ваша среда разработки? Я говорю Android SDK и мобильный?
Я использую SDK уровня 28
Устройство Asus ZenPone 3

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Android SDK 25.2.5

AndroidManifest.template.xml: <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="26" />

Phones: Samsung Galaxy S3, S4, S5, S6,  S7, S8

Samsung Note 3, 4, 5

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я еще не тестировал приложения на Android 9, поэтому не готов подсказать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, Tumaso сказал:

Eu não testei aplicativos no Android 9, por isso não estou pronto para informá-lo

Я изменил sdk на используемую вами версию. Я сделал изменения, и ошибка все еще осталась, и довольно разочаровывающе.

Документация Embarcadero в примере, даже событие «OnDidFinishTaking» прошло, но в вашем и «ноль», по документации и тем, что я прочитал, и правильно, но я все еще получаю ошибку.

 

procedure TForm1.SpeedButton2Click(Sender: TObject);
var
  ImageService: IFMXTakenImageService;
  Params: TParamsPhotoQuery;
begin
  if TPlatformServices.Current.SupportsPlatformService(IFMXTakenImageService,
    IInterface(ImageService)) then
  begin
    Params.RequiredResolution := TSize.Create(640, 640);
    Params.OnDidFinishTaking := DoDidFinish;
    ImageService.TakeImageFromLibrary(SpeedButton2, Params);
  end;
end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу