Android Tutorial DoEvents deprecated and async dialogs (msgbox)

Starting from B4A v7.0 the following warning will appear for DoEvents calls:
DoEvents is deprecated. It can lead to stability issues. Use Sleep(0) instead (if really needed).

The purpose of DoEvents was to allow the UI to be updated while the main thread is busy. DoEvents which shares the same implementation as the modal dialogs implementation, is a low level implementation. It accesses the process message queue and runs some of the waiting messages.

As Android evolved, the handling of the message queue became more sophisticated and fragile.
The reasons for deprecating DoEvents are:

1. It is a major source for instability issues. It can lead to hard to debug crashes or ANR (application not responding) dialogs. Note that this is also true for the modal dialogs (such as Msgbox and InputList).
2. There are better ways to keep the main thread free. For example use the asynchronous SQL methods instead of the synchronous methods.
3. It doesn't do what many developers expect it to do. As it only handles UI related messages, most events could not be raised from a DoEvents call.
4. It is now possible to call Sleep to pause the current sub and resume it after the waiting messages are processed. Sleep implementation is completely different than DoEvents. It doesn't hold the thread. It instead releases it while preserving the sub state.
Unlike DoEvents which only processed UI related messages, with Sleep all messages will be processed and other events will be raised.
(Note that using Wait For to wait for an event is better than calling Sleep in a loop.)

With that said, DoEvents is still there and existing applications will work exactly as before.

Dialogs

Modal dialogs = dialogs that hold the main thread until the dialog is dismissed.

As written above, modal dialogs share the same implementation as DoEvents. It is therefore recommended to switch to the new async dialogs instead. Using Wait For it is really a simple change:

Instead of:
B4X:
Dim res As Int = Msgbox2("Delete?", "Title", "Yes", "Cancel", "No", Null)
If res = DialogResponse.POSITIVE Then
  
End If
You should use:
B4X:
Msgbox2Async("Delete?", "Title", "Yes", "Cancel", "No", Null, False)
Wait For Msgbox_Result (Result As Int)
If Result = DialogResponse.POSITIVE Then
   '...
End If

Wait For doesn't hold the main thread. It instead saves the current sub state and releases it. The code will resume when the user clicks on one of the dialog buttons.
The other similar new methods are: MsgboxAsync, InputListAsync and InputMapAsync.

With the exception of MsgboxAsync, the new methods also add a new cancelable parameter. If it is true then the dialog can be dismissed by clicking on the back key or outside the dialog. This is the default behavior of the older methods.

As other code can run while the async dialog is visible, it is possible that multiple dialogs will appear at the same time.
If this case is relevant for your app then you should set the sender filter parameter in the Wait For call:
B4X:
Dim sf As Object = Msgbox2Async("Delete?", "Title", "Yes", "Cancel", "No", Null, False)
Wait For (sf) Msgbox_Result (Result As Int)
If Result = DialogResponse.POSITIVE Then
   '...
End If
This allows multiple messages to be displayed and the result events will be handled correctly.

Bug in B4A v7.00 / 7.01 - Async dialogs should not be used in classes as the Result event will be raised in the Activity instead of the class module. This is fixed for the next update.
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Thank you Mr Erel.

Considering that there are some libraries or classes that use DoEvents to wait for the outcome of an event, as it has pointed out to objects similar to the MsgBox or other dialog objects,
Of course they must be updated for version 7 with the comand wait.

My question is this.
For the future, do you need to produce libraries or classes for versions 7 that use wats or earlier versions that use DoEvents?
Is a specific API required to run the wait command?
Compiled libraries with B4A version 7 using the wait command can be used with previous versions of B4A?
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Thank's
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
It would be transparent and silently move everything forward.
It will not be transparent. See the resumable subs tutorial: [B4X] Resumable Subs - Sleep / Wait For

1. Resumable subs cannot return a value.
2. The code flow is different. Calling Sleep or Wait For is equivalent to calling Return from the caller sub perspective.
 
Last edited:

Widget

Well-Known Member
Licensed User
Longtime User
Erel, when you say:
1. Resumable subs cannot return a value.
2. The code flow is different. Calling Sleep or Wait For is equivalent to calling Return from the caller sub perspective.​

1) That rule applies all functions and subs that modify parameters like Map or List, correct?

2) Will CustomListView be changed to remove the "DoEvents" entirely?
(Some of the Subs like getHeight, getWidth are functions)

3) Are there built in conditional variables for B4X version number so it can be used as:

B4X:
#IF $VER > 6.5
...
#END IF

#IF $VER = 7
..
#END IF


#IF $PROD = "B4A"
  .. B4A Code ..  
#ELSE
  #IF $PROD = "B4I"
     ... B4i Code ...
  #END IF
#END IF

TIA
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
1) You can do everything that you like in the resumable sub, including modifying lists or maps or global variables, except of calling Return <value here>.

2) There are no DoEvents calls in the latest version of CustomListView. In the past DoEvents was used to immediately change the scroll position. This is no longer required as you can instead use ScrollView.ScrollToNow.

3) Product symbols are available: https://www.b4x.com/android/forum/t...mpilation-build-configurations.40746/#content
There are no built-in symbols for versions.
 

ilan

Expert
Licensed User
Longtime User
Thank you very much for this erel. This is a very impotant addition to b4a.

I have a small question please.

Do time/date dialogs also hold the main thread until the user response?

If yes is there a similar solution for date and timedialog?

Thank you
 

ilan

Expert
Licensed User
Longtime User
the resumable sub function is really awesome. i use it in many cases and works great. it saves a lot headache using csu instead.

i just dont understand something in this code:

B4X:
Msgbox2Async("Delete?", "Title", "Yes", "Cancel", "No", Null, False)
Wait For Msgbox_Result (Result As Int)
If Result = DialogResponse.POSITIVE Then
   '...
End If

in the wait for line you say in the code to wait for the sub Msgbox_Result (Result As Int)

so in the beginning i created this sub manually and returned the value but then i noticed that i don't need to create it but i don't understand from where the result is returned??

is it returned from this line? is like putting 2 subs in 1 sub together and when the user hit the msgbox button it will return from that line?
 

derez

Expert
Licensed User
Longtime User
What do you do with this sub that has to return a value ?
B4X:
Sub Activity_KeyPress (KeyCode As Int) As Boolean
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        Dim k As Int = Msgbox2(......)
        If k =  DialogResponse.NEGATIVE Then Return True
    End If
    Return False
End Sub
 

ilan

Expert
Licensed User
Longtime User
What do you do with this sub that has to return a value ?
B4X:
Sub Activity_KeyPress (KeyCode As Int) As Boolean
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        Dim k As Int = Msgbox2(......)
        If k =  DialogResponse.NEGATIVE Then Return True
    End If
    Return False
End Sub

maybe like this:

B4X:
Private returnValue As Boolean

'...

Sub Activity_KeyPress (KeyCode As Int) As Boolean
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        msgb("Exit App?", "Exit")
        If returnValue Then Return True
    End If
    Return False
End Sub

Sub msgb(txt As String, title As String)
    returnValue = False
    Dim sf As Object = Msgbox2Async(txt, title, "Yes", "Cancel", "No", Null, False)
    Wait For (sf) Msgbox_Result (Result As Int)
    If Result = DialogResponse.POSITIVE Then
        returnValue = True
    End If
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
What do you do with this sub that has to return a value ?
This code is simpler and doesn't use a global variable:
B4X:
Sub Activity_KeyPress (KeyCode As Int) As Boolean 'Return True to consume the event
   If KeyCode = KeyCodes.KEYCODE_BACK Then
     ShouldCloseActivity
     Return True 
   End If
   Return False
End Sub

Private Sub ShouldCloseActivity
   Dim sf As Object = Msgbox2Async(...)
   Wait For (sf) Msgbox_Result (Result As Int)
   If Result Then Activity.Finish
End Sub
 

ilan

Expert
Licensed User
Longtime User
i wrote my code like this because this is a way to return a value.

What do you do with this sub that has to return a value ?

if its only to perform an action like finish the app then erels solution is better but unfortunately if you want to return a value i dont see a way without using a global variable (from a resumeable sub).
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
if its only to perform an action like finish the app then erels solution is better but unfortunately if you want to return a value i dont see a way without using a global variable (from a resumeable sub).
It is not possible to show a modal dialog or call DoEvents inside the Activity_KeyPress event. Starting from Android 4.3 it causes a low level crash.

As I knew that this sub is mainly used with code similar to the one you posted, I added a check for the back key and it actually uses a solution similar to CallSubDelayed and then closes the activity based on the return value. If you try to show a modal dialog when the pressed key is not the back key then it will crash.
You can see it mentioned here: https://www.b4x.com/android/help/views.html#activity
The point is that async dialogs are always better (safer) than the modal dialogs.

you want to return a value i dont see a way without using a global variable (from a resumeable sub).
You don't need a global variable. You need to return the value with CallSubDelayed.
https://www.b4x.com/android/forum/threads/b4x-resumable-subs-sleep-wait-for.78601/page-3#post-506651
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Bug in B4A v7.00 / 7.01 - Async dialogs should not be used in classes as the Result event will be raised in the Activity instead of the class module. This is fixed for the next update.

Hi Erel - I have exactly this issue in a project I'm currently working on. Any idea when the fix will be released?

- Colin.
 
Top