Android Question MsgBox2Async correct use

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Hi to all
since the introduction of asyncronous msgboxes, i lost a good part of love for B4A. As a matter of fact, a trivial action like to wait for user interaction, normally managed in "Modal" style (Windows Modal, I mean) became a nightmare, expecially in previous code written with "obsolete" MsgBoxes. My understanding is that, in practice, I must make Apps more or less without relying on the fact that the App waits for user answers. This adds real difficulties to my common Apps. Therefore I decided to try to understand better my faults on this subject, submitting to this community my problem. In the attached code, I have a List, that needs to be changed on User's choice. This code doesn't work, because the ModifyList returns immediately. Maybe the solution is to let the ModifyList sub to wait too.. but it is not so clear to me what to do.
Thanks in advance

B4X:
Private Sub Button1_Click
    Dim i As Int
 
   List1.Initialize
    
    For i=0 To 10
        List1.Add(i+1)
    Next
    
    Log("Before")
    For i=0 To 10
        Log(List1.Get(i))
    Next
    
    ModifyList(List1)
    
    Log("After")
    For i=0 To 10
        Log(List1.Get(i))
    Next
    
End Sub

private Sub ModifyList(L As List)
    Wait for (Confirm("Modify List?")) Complete (Res As Int)
    If Res=DialogResponse.POSITIVE Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
    End If
End Sub

private Sub Confirm(Msg As String) As ResumableSub
    Dim Res As Int
    Msgbox2Async(Msg, "Attention", "Yes", "", "No",Null, False)
    Wait For Msgbox_Result (Res As Int)
    Return Res
End Sub
 

Attachments

  • TestAsyncMsgbox.zip
    10.1 KB · Views: 200

Brian Dean

Well-Known Member
Licensed User
Longtime User
Since the introduction of asyncronous msgboxes, i lost a good part of love for B4A.
You speak as though asynchronous msgboxes were created by B4A. In fact blocking message boxes were always a bit of a workaround, I think, and asynchronous boxes are the underlying style that Android (not B4A) expected. So I don't think this is B4A's fault.

But in anycase by providing the "Wait for ..." construct B4A makes the asynchronous option almost as easy to use as the older form. What is more the pop-up help box for MsgBoxAsync provides a cut-and-paste model for you to use - check it out.

So, to get round to answering your question (at last) here is what I think is the correct way to code your example ...
B4X:
Private Sub modifyList
    Dim sf As Object = xui.Msgbox2Async("Modify list?", "Attention", "Yes", "", "No", Null)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
    End If
End Sub
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Be aware that when you call ModifyList(List1) in Button1_Click, the code after is executed directly after the call.
So, if you want to show the modified list you must put the code after the Wait.

B4X:
Private Sub modifyList
    Dim sf As Object = xui.Msgbox2Async("Modify list?", "Attention", "Yes", "", "No", Null)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
        
        Log("After")
        For i=0 To 10
            Log(List1.Get(i))
        Next
    End If
End Sub
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
As a early design decision the Android UI doesn't support modal anything. The original blocking dialogs were implemented within B4A and pumped the message loop to keep the UI alive without actually returning to the message loop itself. Unfortunately over time the message loop handling within Android got more and more complicated and the modal mechanism became more and more fragile and eventually Erel had to throw in the towel, deprecate modality and implement the asynchronous dialogs.

Once you get familiar with them they are as easy to use as the modal dialogs. Just remember that Sleep and Wait For actually cause an immediate return from their Sub so further code in the calling Sub will execute unless it too waits for the called Sub to complete.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
You speak as though asynchronous msgboxes were created by B4A. In fact blocking message boxes were always a bit of a workaround, I think, and asynchronous boxes are the underlying style that Android (not B4A) expected. So I don't think this is B4A's fault.

But in anycase by providing the "Wait for ..." construct B4A makes the asynchronous option almost as easy to use as the older form. What is more the pop-up help box for MsgBoxAsync provides a cut-and-paste model for you to use - check it out.

So, to get round to answering your question (at last) here is what I think is the correct way to code your example ...
B4X:
Private Sub modifyList
    Dim sf As Object = xui.Msgbox2Async("Modify list?", "Attention", "Yes", "", "No", Null)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
    End If
End Sub
Substituting my Sub with yours, changes nothing, if I don't miss anything (could be, of course).. unluckily. Thanks anyway
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
As a early design decision the Android UI doesn't support modal anything. The original blocking dialogs were implemented within B4A and pumped the message loop to keep the UI alive without actually returning to the message loop itself. Unfortunately over time the message loop handling within Android got more and more complicated and the modal mechanism became more and more fragile and eventually Erel had to throw in the towel, deprecate modality and implement the asynchronous dialogs.

Once you get familiar with them they are as easy to use as the modal dialogs. Just remember that Sleep and Wait For actually cause an immediate return from their Sub so further code in the calling Sub will execute unless it too waits for the called Sub to complete.
I blame Erel and B4A. My problem remains, anyway. Thanks.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Be aware that when you call ModifyList(List1) in Button1_Click, the code after is executed directly after the call.
So, if you want to show the modified list you must put the code after the Wait.

B4X:
Private Sub modifyList
    Dim sf As Object = xui.Msgbox2Async("Modify list?", "Attention", "Yes", "", "No", Null)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
      
        Log("After")
        For i=0 To 10
            Log(List1.Get(i))
        Next
    End If
End Sub
You by passed my question, which is teoretical, extracted from a real App, in which the. The conclusion is that my trivial example has no solution.
Before answering post #3 I tested your project.
And attached the result.
So, what is the problem ?
Sorry Klaus, I was answering and sent the comment improperly. I will check your suggestion. Thanks.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Before answering post #3 I tested your project.
And attached the result.
So, what is the problem ?
The problem is as I described: as I was writing in my previous incomplete answer, it is not the matter of updating a list and see a Log. I cannot post my entire project, because it has too many dependencies. In a complex flow, I need to ask a user to confirm an action, exactly as I I wrote in my code. In other words, I need a "modal dialog box". After the call to the ModifyList, there is other code which takes the eventually modified elements, calling other subs, etc. etc..
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
You by passed my question, which is teoretical, extracted from a real App, in which the. The conclusion is that my trivial example has no solution.

Sorry Klaus, I was answering and sent the comment improperly. I will check your suggestion. Thanks.
Probabilmente nel forum italiano ci capiremmo meglio ;)
Probably in the Italian forum we would understand each other better

It is useful and important to understand how "Wait For" work and should be used, not only for the Msgbox2Async.

However, still using the MsgBoxes is not a big risk, since usually the user responds "quickly".
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Luca
Probabilmente nel forum italiano ci capiremmo meglio ;)
Probably in the Italian forum we would understand each other better

It is useful and important to understand how "Wait For" work and should be used, not only for the Msgbox2Async.

However, still using the MsgBoxes is not a big risk, since usually the user responds quickly.
Temo che in futuro i geni di Google blocchino completamente i MsgBoxes.
I fear that , in future, Google geniuses will completely block MsgBoxes..
 
Upvote 0

Brian Dean

Well-Known Member
Licensed User
Longtime User
Substituting my Sub with yours, changes nothing . . .
Yes - I misunderstood your problem. I have a better suggestion now, although @klaus example might be better.

B4X:
Sub Globals
    Dim xui As XUI
    Dim List1 As List
    Dim checking As Boolean = False
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
End Sub

Private Sub Button1_Click
    Dim i As Int
     List1.Initialize
     For i=0 To 10
        List1.Add(i+1)
    Next 
    Log("Before")
    For i=0 To 10
        Log(List1.Get(i))
    Next
    
    checking = True    ' This allows you to wait for the User
    modifyList
    Do While checking  ' Wait until the resumable sub is finished
        Sleep(0)
    Loop
    
    Log("After")
    For i=0 To 10
        Log(List1.Get(i))
    Next
End Sub

Private Sub modifyList
    Dim sf As Object = xui.Msgbox2Async("Modify list?", "Attention", "Yes", "", "No", Null)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Dim i As Int
        For i=0 To 10
            List1.Set(i,10-i)
        Next
    End If
    checking = False
End Sub
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Luca

Temo che in futuro i geni di Google blocchino completamente i MsgBoxes.
I fear that , in future, Google geniuses will completely block MsgBoxes..
The trouble that could happen is that the OS kills your app (process) because it thinks it is blocked.
This is the case if the MsgBox remained on the screen for more than a few minutes, probably something that doesn't happen, because the user uses your app and replies to the message in just a few seconds.

However, again, it is important that you (all of us) learn to use Wait For well, regardless of MsgAsync
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
To be able to give a concrete answer you need to give more information.
You will probably need to change the structure of your code when using Wait For.
The code after it will directly be executed. The main thread will not be stopped to wait.
All the code depending on the response of the wait for must be treated in the test of the response.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
To be able to give a concrete answer you need to give more information.
You will probably need to change the structure of your code when using Wait For.
The code after it will directly be executed. The main thread will not be stopped to wait.
All the code depending on the response of the wait for must be treated in the test of the response.
Sorry Klaus: more information than code, what can I post? Anyway, some of my Apps where developed before the MsgBox deprecation. They are very complex, sometimes. My "illusion" was that my Confirm sub was "Modal". As you see in my code, the idea is to stop execution until the user says Yes/No and go further. The syntax is misleading: as you see there is a double Wait for, one in Confirm and the other in ModifyList. In ModifyList, I (wrongly) thought that the App should wait for Confirm completion..
B4X:
private Sub ModifyList(L As List)
    Wait for (Confirm("Modify List?")) Complete (Res As Int)
    If Res=DialogResponse.POSITIVE Then
        Dim i As Int
        For i=0 To 10
            L.Set(i,10-i)
        Next
    End If
End Sub

private Sub Confirm(Msg As String) As ResumableSub
    Dim Res As Int
    Msgbox2Async(Msg, "Attention", "Yes", "", "No",Null, False)
    Wait For Msgbox_Result (Res As Int)
    Return Res
End Sub
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
If MsgAsync complicates your existing project, don't use it, continue with MsgBox.

For new projects you will use it, after having understood the functioning of "Wait For".
Unluckily I understood. This is the problem. Thanks (grazie comunque)
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Sorry Klaus: more information than code, what can I post? Anyway, some of my Apps where developed before the MsgBox deprecation. They are very complex, sometimes. My "illusion" was that my Confirm sub was "Modal". As you see in my code, the idea is to stop execution until the user says Yes/No and go further. The syntax is misleading: as you see there is a double Wait for, one in Confirm and the other in ModifyList. In ModifyList, I (wrongly) thought that the App should wait for Confirm completion..
Since your ModifyList Sub contains a "Wait For" statement, it is too a resumable Sub, so you may need to call it too using a "Wait For"!
 
Last edited:
Upvote 0
Top