Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   einfacher Waiting-Indicator für Android (https://www.delphipraxis.net/205026-einfacher-waiting-indicator-fuer-android.html)

philipp.hofmann 24. Jul 2020 13:23

einfacher Waiting-Indicator für Android
 
Hi,

ich versuche gerade einen ganz einfachen Waiting-Indicator für Android darzustellen. Unter Windows und MacOS ja ganz einfach, einfach crHourGlass bzw. crDefault anzeigen und gut ist, das funktioniert auch im MainThread. Unter iOS und Android ist es ja jetzt etwas schwieriger v.a. wenn man die eigentliche Operation im MainThread durchführt. Ein TAniIndicator bewegt sich da dann leider nicht.
Ich habe daher ein einfaches TImage genommen und ein Sandbox-Bild reingeladen (reicht mir aus, Hauptsache der User weiß, dass gerade etwas passiert).
Normalerweise ist dieses Image versteckt und wenn man etwas klickt, wird es an der Stelle des Klick/Tap angezeigt.

Klappt unter iOS wunderbar. Unter Android sehe ich aber nichts (auch nicht, wenn ich ein sleep(1000) einfüge).
Das es an sich an der richtigen Stelle platziert ist, weiß ich, weil ich in hideHourGlass das isVisible:=false mal auskommentiert habe und
dann sehe ich das Warten-Symbol an der Stelle der letzten Aktion, wo es eingeblendet wurde.

D.h. meine Frage ist, wie bekomme ich das Display unter Android aktualisiert?

Grüße, Philipp

Delphi-Quellcode:
procedure TicTrainerF.showHourglass(sender:TObject);
begin
  {$if defined(IOS) or defined(ANDROID)}
    if ((sender<>nil) and (sender is TControl)) then
    begin
      progressArc.Position:=(sender as TControl).Position;
      progressArc.Parent:=(sender as TControl).Parent;
    end else begin
      progressArc.Position.X:=50;
      progressArc.Position.Y:=50;
      progressArc.Parent:=self;
    end;
    progressArc.Visible:=true;
    progressArc.repaint();
    Application.ProcessMessages();
  {$ELSE}
    if (cs<>nil) then
      cs.SetCursor(crHourGlass);
  {$ENDIF}
end;

procedure TicTrainerF.hideHourglass();
begin
  {$if defined(IOS) or defined(ANDROID)}
    progressArc.Visible:=false;
  {$ELSE}
    if (cs<>nil) then
      cs.SetCursor(crDefault);
  {$ENDIF}
end;

Rollo62 24. Jul 2020 13:33

AW: einfacher Waiting-Indicator für Android
 
Du musst wahrscheinlich schon den Aufruf asynchron machen.
Ich arbeite z.B. oft mit TThread.ForceQueue, geht an jeder Stelle und schadet nicht.
Kann aber blockierende Tasks schön entkoppeln.

Delphi-Quellcode:
  ShowIndicator;

  TThread.ForceQueue(
    nil,
    procedure
    begin
       DoBlockingStuff;
    end );

Ach ja, und ApplicationProcessMessages würde ich möglichst Vermeiden, das richtet mehr Schaden an als es nutzt.

philipp.hofmann 24. Jul 2020 14:10

AW: einfacher Waiting-Indicator für Android
 
Genau das mit dem asynchronen Aufruf will ich ja vermeiden, ich will den unter Windows/MacOS/iOS laufenden Code ja nicht anpassen müssen.
Es ist ja okay, dass alles blockiert ist, da geht es auch nur um 1-3 Sekunden, wo der Anwender geduldig sein soll.

Es geht ja "nur" darum, dass davor erfolgreich ein Image eingeblendet wird.
P.S.: Unter iOS war das Application.processMessages notwendig, damit das Image angezeigt wird.

Rollo62 24. Jul 2020 14:43

AW: einfacher Waiting-Indicator für Android
 
Ok, aber ich habe mis Sanchrone schon abgewöhnt.
Es führt immer wieder zu seltsamen Verhalten auf den mobilen Platformen.
Ich kann nur empfehlen möglichst entkoppeln und asynchron halten.

Übrigens würde das in deinem Beispiel wohl auch auf dem Desktop nicht immer korrekt Updaten blockieren.
Wenn nach dem Show direkt was blockiert kann es da genauso haken.

himitsu 24. Jul 2020 14:46

AW: einfacher Waiting-Indicator für Android
 
Das Queue/ForceQueue ist kein Thread ... es wartet auch, nur eben nicht sofort, sonder erst dann, wenn beim nächsten Mal die MessageQueue verarbeitet wird.
Stell es dir wie ein PostMessage oder einen TTimer mit 1 Millisekunden vor, den du statest und später wird der Code ausgeführt (und der Timer wieder gestoppt).
Bzw. das ForceQueue ist fast wie ein ProcessMessages vor dem folgenden/enthaltenen Code.

OK, bei paar wenigen Sekunden nicht unbedingt nötig, aber ein Thread wäre für längere Pausen schon die bessere Lösung.


Am Besten immer ForceQueue verwenden, denn das ist der Bugfix, da jemand auf die geile Idee kam dass wenn man Queue im Hauptthread benutzt, dann wird es sofort ausgeführt, anstatt es in die Queue zu stecken.

Rollo62 24. Jul 2020 17:34

AW: einfacher Waiting-Indicator für Android
 
Ja das ForeceQueue ist kein Thread, man kann es im MainUi oder Thread nutzen ohne das es Probleme macht.
Ich meinte ja das es den Aufruf etwas asynchron feuert, wenn z.b. ein Event schon verlassen wurde.
Das reicht meist damit ein Refresh ordentlich gezeichnet wird,
bevor das Blocking startet.
Hatte vorher ein Delay drin, das nehme ich aber nur noch in Härtefällen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:56 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