Перейти к содержанию
Fire Monkey от А до Я
  • 0

Firemonkey TTakePhotoFromCameraAction.OnDidFinishTaking causes my app to restart


Alisson R Oliveira

Вопрос

привет привет
у кого-то были проблемы с «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

Ссылка на комментарий

Рекомендуемые сообщения

  • 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

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
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;
Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

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

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