German Resumable Sub

peternmb

Well-Known Member
Licensed User
Longtime User
Hallo,

vielleicht kann mir jemand in einfachen Worten anhand meines Beispieles erklären was das für meinen Code bedeutet.
Ich habe jetzt allerlei Tutorials und Beiträge gelesen ohne daraus richtig schlau zu werden.

Ich lagere gelegentlich Funktionen die ich öfters benötige als Subs aus, um bei Bedarf einfach darauf zurückgreifen zu können oder um meinen Code übersichtlicher zu machen.

Ich habe z.B. das Laden der Grundkonfiguration in eine sub "load_ini" ausgelagert.
Dort wird geprüft, ob eine ini-Datei vorhanden ist und von dort die Werte eingelesen, falls nicht vorhanden wird die ini-Datei mit Standardwerten erstellt.
Diese Sub wurde als "resumable sub" gekennzeichnet, was mir irgendwann eunmal ufgefallen ist - ich habe mich aber nicht weiter darum gekümmert...
Mein Code sah etwa so aus:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        SP.Initialize(4)
        LoadId1 = SP.Load(File.DirAssets, "sound1.wav")
        LoadId2 = SP.Load(File.DirAssets, "sound2.wav")
        VR.Initialize("VR")
        lblF1.Initialize("lblF1")
        lblF2.Initialize("lblF2")
    End If
    '
    Bild0.Initialize(File.DirAssets, "password32.png")
    Bild1.Initialize(File.DirAssets, "settings32.png")
    '
    load_ini
    '
   '
    ' und weiter geht es, aber es werden Werte aus der ini-Datei
   ' benötigt die anscheinend noch nicht da sind und die App crasht
   '
Wie kann ich dafür sorgen, dass bevor es in der App weitergeht die sub load_ini erst komplett abgearbeitet wird?
 

b4x-de

Active Member
Licensed User
Longtime User
Hallo,

Im Prinzip musst du den Aufruf deiner load_ini mit einem Wait For kombinieren. Das Wait For sorgt meinem Verständnis nach dafür, dass die Auführung der Create_Activity zunächst unterbrochen wird und damit die Kontrolle über die Verarbeitung an das Betriebssystem übergeben wird. (Das ist wichtig, damit lange laufende Operationen, z.B. eine Netzwerkkommunikation nicht die Verarbeitung blockiert.) Sobald das Ergebnis deiner load_ini vorliegt, wird an der Stelle mit dem Wait For die weitere Verarbeitung in der Create_Activity fortgesetzt.

Meine Erfahrung ist, dass ein Wait For allerdings nicht ausreicht. Stattdessen ist es besser, dass auf das Vorliegen des Ergebnisses explizit gewartet wird. Dazu muss die load_ini ein Ergebnis zurückliefern. Momentan ist load_ini bei dir eine Prozedur. Du musst daraus eine Funktion machen und mit dem Return einen Wert zurückliefern. Dann kannst du Wait For(load_ini) Complete (result As <Datentyp des Rückgabewertes>) schreiben. Beispielsweise so:

B4X:
Sub Activity_Create(FirstTime As Boolean)
' ...
Wait For(load_ini) Complete (result As Int)
' ...
End Sub

Sub load_ini() As ResumableSub ' Rückgabewert vom Typ Int

'...

  Return 1
End Sub

Oder alternativ entsprechend eines Vorschlags von Erel. (Ich finde den Post nicht mehr, wo er es vorgeschlagen hat.)

B4X:
' Alterantiv der Vorschlag von Erel

Sub Activity_Create(FirstTime As Boolean)
' ...
Wait For(load_ini) Complete (result As Object)
' ...
End Sub

Sub load_ini() As ResumableSub ' Rückgabewert vom Typ Object

'...

  Return Null
End Sub

Es gibt eine wichtige Stolperfalle: Sobald eine Prozedur oder Funktion als Resumable deklariert wurde, infiziert sie damit alle anderen Prozeduren und Funktionen, die sie aufrufen. Das bedeutet, erheblichen Aufwand falls man wiederverwendbare Funktionen hat. Außerdem macht der Compiler bei Funktionen keine Typprüfung des Rückgabewertes. Deshalb produzieren Resumable Subs leichter Laufzeitfehler.

Ich finde übrigens auch, dass trotz der vielen Beiträge und Erels Tutorials das Thema ansynchroner Programmierung mit Resumable Subs in B4X nicht gut verständlich ist.

Weiterhin viel Erfolg!

Thomas
 

OliverA

Expert
Licensed User
Longtime User
Mann muss beachten dass ein wait for in activity_create dazu führt dass activity_resume aufgerufen wird obwohl activity_create noch nicht fertig ausgeführt ist (falls noch mehr code nach dem wait for stehen)
 

peternmb

Well-Known Member
Licensed User
Longtime User
Ist eigentlich genau so, wie ich es bereits vermutet habe.

Was mich dabei irritiert: ich bin es aus dem Programmieren unter Windows gewohnt, dass Aktionen die in einem Thread (ist vermutlich unter B4A Activity) ablaufen der Reihe nach abgearbeitet werden, mehrere Threads natürlich parallel.

Da machen dann eigentlich die resumable Subs nicht wirklich Sinn, oder wofür kann man die sinnvoll einsetzen nutzen?
 

b4x-de

Active Member
Licensed User
Longtime User
Hallo,

Resumable Subs muss man immer dann benutzen, wenn lange laufende Operationen die eigene App blockieren. Beispielsweise, wenn man auf Netzwerkkommunikation wartet oder auf lange laufende Dateioperationen. Andernfalls würde Android "denken", dass die App abgestürzt ist und nicht mehr reagiert. Der Benutzer bekommt dann die typische Meldung, ob er warten oder die App beenden will.

Weil mit Resumable Subs stattdessen die Kontrolle an das Betriebssystem übergeht und erst zurückkehrt, wenn das Ergebnis vorliegt, blockiert die App nicht. Android nimmt seine Aufgabe als Betriebssystem vielleicht etwas ernster als Windows und kümmert sich deshalb strenger um die verwalteten Ressourcen...

Viele Grüße
Thomas
 

OliverA

Expert
Licensed User
Longtime User
Was mich dabei irritiert: ich bin es aus dem Programmieren unter Windows gewohnt, dass Aktionen die in einem Thread (ist vermutlich unter B4A Activity) ablaufen der Reihe nach abgearbeitet werden,
Android <> Windows
 

peternmb

Well-Known Member
Licensed User
Longtime User
Weil mit Resumable Subs stattdessen die Kontrolle an das Betriebssystem übergeht und erst zurückkehrt, wenn das Ergebnis vorliegt, blockiert die App nicht. Android nimmt seine Aufgabe als Betriebssystem vielleicht etwas ernster als Windows und kümmert sich deshalb strenger um die verwalteten Ressourcen...
Halte ich nicht unbedingt für einen Vorteil - mir ist es lieber selber die Kontrolle zu behalten.
 

OliverA

Expert
Licensed User
Longtime User
mir ist es lieber selber die Kontrolle zu behalten
Mit Android? LOL. Mit jeder Version hat der Developer weniger und weniger Kontrolle. Android und der Benutzer sind in Kontrolle. Wait For gibt dir einen weg etwas zu tun damit Android deine App nicht zwanghaft schließt. Brauchst du zu lange in Activity_Create? Android killt die App. Blockierst du die UI? Android killt die App. Android langweilt sich? Killt die App. Willst du mit Android um Kontrolle kämpfen? Kill. Du hasst nicht mal Kontrolle deine App zu beenden. Android tut das. Und ab und zu sagt Android dir Bescheid. Und ab und zu hat deine App null Ahnung das es geschlossen wurde. Benützt du zu viel Batterie? Tot. Willst du ein bisschen zu lange im Hintergrund bleiben? Tot. Und das ist nur Stock Android. Manche Hersteller wollen "besser" sein als Android und finden mehr Wege den Developer das Bein zu stellen (https://www.b4x.com/android/forum/threads/”hey-android-vendors-don’t-kill-my-app-”.101495/#content).
 

peternmb

Well-Known Member
Licensed User
Longtime User
vielen Dank für die Hinweise und dem sehr interssanten Link.

Ich war bei Android-4, als ich mit B4A begonnen habe, begeistert von der einfachen Art des Programmierens im Gegensatz zu Windows.
Leider verflüchtigt sich die Freude mit jeder neuen "besseren" Android-Version...
 

OliverA

Expert
Licensed User
Longtime User
Top