Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   FMX unbekannten Thread synchronisieren (https://www.delphipraxis.net/209173-fmx-unbekannten-thread-synchronisieren.html)

friedt99 4. Nov 2021 20:46

FMX unbekannten Thread synchronisieren
 
Hallo Zusammen,

habe folgendes Problem (D11, FMX, IOS):

Delphi-Quellcode:
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  System.Notification, FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    NotificationCenter1: TNotificationCenter;
    procedure Button1Click(Sender: TObject);
    procedure NotificationCenter1PermissionRequestResult(Sender: TObject;
      const AIsGranted: Boolean);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation
uses FMX.DialogService;

{$R *.fmx}



procedure TForm1.Button1Click(Sender: TObject);
begin
  if NotificationCenter1.AuthorizationStatus <> TAuthorizationStatus.Authorized then
  begin
    NotificationCenter1.RequestPermission;
  end;
end;

procedure TForm1.NotificationCenter1PermissionRequestResult(Sender: TObject;
  const AIsGranted: Boolean);
begin
  if not AIsGranted then
  begin
    TDialogService.ShowMessage
      ('Die App kann Dir keine Nachrichten senden, da die erforderliche Berechtigung dazu nicht erteilt wurde.');
  end;
end;

end.
Wenn man "nicht zulassen" auswählt bei der Abfrage auf dem Smartphone, wird NotificationCenter1PermissionRequestResult aufgerufen.
Das crasht dann mit "Im Projekt Project1 ist eine Exception der Klasse Exception mit der Meldung 'Meldungen müssen im Haupt-UI-Thread angezeigt werden.' aufgetreten."

Das kommt vom TDialogService.ShowMessage.

Kann ich, und wenn ja, wie, den "unbekannten" Thread der NotificationCenter1PermissionRequestResult aufruft, mit dem Mainthread synchronisieren ?

Wenn nein, unter VCL hätte ich jetzt mit einem PostMessage gearbeitet. Gibt es in FMX ein eine äquivalente Möglichkeit dazu ?


Vielen Dank schon mal

Thomas

Uwe Raabe 4. Nov 2021 20:56

AW: FMX unbekannten Thread synchronisieren
 
Nur so aus der Hüfte:
Delphi-Quellcode:
TThread.Synchronize(nil,
  procedure
  begin
    TDialogService.ShowMessage('Die App kann Dir keine Nachrichten senden, da die erforderliche Berechtigung dazu nicht erteilt wurde.');
  end;

friedt99 4. Nov 2021 21:14

AW: FMX unbekannten Thread synchronisieren
 
Du hättest mit deinen Schüssen aus der Hüfte Billy the Kid erledigt....

Bis auf eine fehlende ) war es perfekt.

So klappt es:

Delphi-Quellcode:
procedure TForm1.NotificationCenter1PermissionRequestResult(Sender: TObject;
  const AIsGranted: Boolean);
begin
  if not AIsGranted then
  begin
    TThread.Synchronize(nil,
      procedure
      begin
        TDialogService.ShowMessage('Die App kann Dir keine Nachrichten senden, da die erforderliche Berechtigung dazu nicht erteilt wurde.');
      end);
  end;
end;

Vielen Dank.

Rollo62 5. Nov 2021 07:22

AW: FMX unbekannten Thread synchronisieren
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1497125)
Nur so aus der Hüfte:
Delphi-Quellcode:
TThread.Synchronize(nil,


Ich mache das gerne so wie unten, mit ForceQueue statt mit Synchronize,
um noch mehr auf der sicheren Seite zu sein.
Das würde es in allen Thread/NichtTread Fällen gut abkapsel, und man muss sich weniger sorgen machen.

In dem Fall mit der Nutzereingabe ist das Timing o.ä. sowieso völlig irrelevant,
ob es eine ms mehr oder weniger braucht.

Delphi-Quellcode:
TThread.ForceQueue(nil,
  procedure
  begin
    TDialogService.ShowMessage('Die App kann Dir keine Nachrichten senden, da die erforderliche Berechtigung dazu nicht erteilt wurde.');
  end;

himitsu 5. Nov 2021 09:31

AW: FMX unbekannten Thread synchronisieren
 
Bei Queue/ForceQueue mußt du nur aufpassen, wenn du übergreifende Variablen verwendest, dass deren Inhalt (Objekte, Zeiger und bedingt auch dynamische Arrays) zur Ausführungszeit noch vorhanden ist. (oder für den Aufruf vorher kopiert werden)

Rollo62 5. Nov 2021 09:50

AW: FMX unbekannten Thread synchronisieren
 
Zitat:

Zitat von himitsu (Beitrag 1497138)
Bei Queue/ForceQueue mußt du nur aufpassen, wenn du übergreifende Variablen verwendest, dass deren Inhalt (Objekte, Zeiger und bedingt auch dynamische Arrays) zur Ausführungszeit noch vorhanden ist. (oder für den Aufruf vorher kopiert werden)

Dankesehr für den Hinweis, himitsu.

Das ist richtig, und das mache ich standardmässig so nach dem Schema wie unten,
und kopiere mir die Variablen lokal, mit dem gleichen Namen, nur mit "A" und "L" unterschiedlich benannt.

Delphi-Quellcode:
procedure TForm.PressIt( AParam : TMyParameter );
var
  LParam : TMyParameter;
begin
  LParam := AParm;

  TThread.ForceQueue(nil,
      procedure
      begin
          TDialogService.ShowMessage( LParam.Message );
      end );

end;
Mit dieser Konfiguration gab es noch nie Probleme (Toi, Toi, Toi),
und ich kann das nur empfehlen :thumb:

Uwe Raabe 5. Nov 2021 10:37

AW: FMX unbekannten Thread synchronisieren
 
Das geht aber auch nur, wenn TMyParameter keine Klasseninstanz ist, die direkt nach dem Aufruf von PressIt freigegeben wird. Auch eine nachträgliche Änderung des Inhalts von Message könnte sich manchmal in der Anzeige wiederfinden.
Zitat:

Zitat von Primož Gabrijelčič
Parallel programming is hard.


Rollo62 5. Nov 2021 11:06

AW: FMX unbekannten Thread synchronisieren
 
Ja ein bischen aufpassen muss man schon noch ...
und notfalls einen Clone lokal erzeugen.
Deshalb das auch besser noch mit Interfaces benutzen,
aber ich glaube wir driften schon etwas ab.

himitsu 5. Nov 2021 11:51

AW: FMX unbekannten Thread synchronisieren
 
Jupp, gerade in dem Beispielcode aus Post #6 ist es egal, da LParam und AParam genau gleich behandelt werden.

Aber wie schon genannt, kommt es teilweise auf den jeweiligen Anwendungsfall an, wo die Lösungen auch unterschiedlich ausfallen können.



Beispiel: wieder der Code aus #6, aber mit noch einem CONST am Parameter, welcher zufällig ein Record mit mehr als 8 Byte ist.
Der Speicher, auf welchen AParam zeigt, der könnte bei Aufruf der Funktion bereits verschwunden oder neu befüllt sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz