Android Question Why is Sleep Needed to Prevent Crash?

JohnC

Well-Known Member
Licensed User
I just spent MANY hours trying to figure this one out :(

So, why is the "Sleep(250)" needed to prevent the below Crash?

Here is my code (ExportSettings is the Starting Sub):

B4X:
Sub Globals
    Dim Zip As ArchiverPlusZip    'ArchivePlusZip 1.13
End Sub

Sub ExportSettings

    Dim SF As List
    SF.Initialize
    SF.Add(File.Combine(SharedDir,"My.db"))
    SF.Add(File.Combine(SharedDir,"myapp_preferences.xml"))
 
    Zip.AddFilesToZip(SF,File.Combine(SharedDir,"myapp_settings.zip"),"Zip")

    'Since I could not figure out how to use a 'Wait For' here, I was forced to use the event sub below

End Sub

Sub Zip_ZipResult(Result As Int, ErrorMsg As String)

    If Result <> Zip.ZIP_RESULT_SUCCESS Then
        Msgbox("There was an Error creating the backup ZIP file, Please try again (" & ErrorMsg & ")","Export Error")
        Return
    End If

    'Sleep(250)    'if I dont have this line, I will get below error

    Wait For(SendEmail(EmailAddress,"Email Subject","Email Body","myapp_settings.zip")) Complete (Res As String)
    If Res <> "" Then
        Msgbox("There was an error sending the email (" & Res & ")" & CRLF & CRLF & "Please Try Again", "Email Error")
    Else
        Msgbox("Email Sent Successfully","Email")
    End If

End Sub

Sub SendEmail (ToEmail As String, EmailSubject As String, EmailBody As String, AttachmentFileName as String) As ResumableSub

    Dim SMTP As SMTP    'Net 1.80
    ...
    ' (code to setup properties of SMTP object)
    ...

    ProgressDialogShow("Sending Email...")

    Dim SS As Object = SMTP.Send
    Wait For (SS) Smtp_MessageSent(Success As Boolean)
 
    ProgressDialogHide

    If Success = False Then
        Return LastException.Message
    Else
        Return ""
    End If
 
End Sub
And this is the error I will get without the Sleep(250):
B4X:
main$ResumableSub_SendEmailresume (java line: 3140)
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    at android.os.Handler.<init>(Handler.java:200)
    at android.os.Handler.<init>(Handler.java:114)
    at android.app.Dialog.<init>(Dialog.java:113)
    at android.app.AlertDialog.<init>(AlertDialog.java:125)
    at android.app.AlertDialog.<init>(AlertDialog.java:109)
    at android.app.ProgressDialog.<init>(ProgressDialog.java:86)
    at android.app.ProgressDialog.show(ProgressDialog.java:131)
    at android.app.ProgressDialog.show(ProgressDialog.java:125)
    at anywheresoftware.b4a.keywords.Common.ProgressDialogShow2(Common.java:742)
    at anywheresoftware.b4a.keywords.Common.ProgressDialogShow(Common.java:731)
    at com.omnisoft.voiceit.main$ResumableSub_SendEmail.resume(main.java:3140)
    at com.omnisoft.voiceit.main._sendemail(main.java:3059)
    at com.omnisoft.voiceit.main$ResumableSub_Zip_ZipResult.resume(main.java:5409)
    at com.omnisoft.voiceit.main._zip_zipresult(main.java:5346)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:196)
    at a.a.a.f.a.a(SourceFile:88)
    at a.a.a.f.a.c(SourceFile:155)
    at a.a.a.f.a.a(SourceFile:163)
    at a.a.a.i.a.a(SourceFile:190)
    at a.a.a.i.a$1.run(SourceFile:1101)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)
 
Last edited:

Sandman

Well-Known Member
Licensed User
Sorry, can't explain or help really, I just wonder if you would also avoid the crash with Sleep(0)?
 

JohnC

Well-Known Member
Licensed User
Sorry, can't explain or help really, I just wonder if you would also avoid the crash with Sleep(0)?
Yes - Sleep (0) will prevent the crashing
 

JohnC

Well-Known Member
Licensed User
Never use DoEvents or Msgbox. Only the non-modal MsgboxAsync.
I am not using any DoEvents, and if I rem out all three MsgBox's - it will still crash without the Sleep(x).
 

JohnC

Well-Known Member
Licensed User

Informatix

Expert
Licensed User
The answer is: the event is mistakenly raised on a background thread. Don't handle this event.

The solution is to modify the library code and change it to be raised with ba.raiseEventFromThread.
I disagree. If I chose to raise this event on a background thread, it is not because I didn't realize the consequence (it is quite obvious when you try to update a view or use functions like MsgBox), but because the alternative solution doesn't match my needs, because it triggers the event too late to be really useful in very concrete cases. I prefer to give the user the choice between executing code at the time the event occurs and executing it in the main thread, but in a delayed way with CallSubDelayed. So it's not a mistake and it won't be changed.
To solve the above case, just put the code of Zip_ZipResult in a different sub and call this sub with CallSubDelayed.
 
Top