Android Question Can't get Wait For to work on two different ZIP libs

JohnC

Well-Known Member
Licensed User
I first tried getting it to work with this one (see end of thread):

https://www.b4x.com/android/forum/threads/sd-ziplibrary.90733/

Then I tried getting it to work with this one:

https://www.b4x.com/android/forum/threads/lib-archiver.21688/

I don't like having a bunch of async subs jumping execution all around the place - hard to read and maintain. So, that's why I want to use Wait For because it keeps code flow clear and contained.

I must be doing something wrong because this is the second ZIP lib I am trying to get working with "Wait For" without any success.

I tried all FOUR "wait for" lines below and the code just hangs on them (obviously I tried them one at a time ;):
(This code is in a sub within the Main Activity)
B4X:
'export app settings
Dim Zip As ArchiverPlusZip
Dim SF As List
SF.Initialize
SF.Add(File.Combine(File1Dir,"mydatabase.db"))
SF.Add(File.Combine(File2Dir,"com.myapp_preferences.xml"))
Zip.AddFilesToZip(SF,File.Combine(ZipDir,"MyApp_Settings.zip"),"Zip")

Wait for ZipResult(Result As Int, ErrorMsg As String)
Wait for (Zip) ZipResult(Result As Int, ErrorMsg As String)
Wait for Zip_ZipResult(Result As Int, ErrorMsg As String)
Wait for (Zip) Zip_ZipResult(Result As Int, ErrorMsg As String)
 
Last edited:

JohnC

Well-Known Member
Licensed User
(I only listed all those waitfor's to show all the different variations I tried - one at a time)

It will work with the separate event sub of:
B4X:
Zip_ZipResult(Result As Int, ErrorMsg As String)
But as I mentioned, having separate event subs makes coding hard to read/follow - that's why Wait For is so helpful.

So I was wondering why I could not get a "Wait For" working to detect the event so I won't have to use a separate sub.
 

JohnC

Well-Known Member
Licensed User
It should be:
B4X:
Wait For Zip_ZipResult(Result As Int, ErrorMsg As String)
If it doesn't work then the event is probably not asynchronously and is raised before the code flow returns from AddFilesToZip method.
The third "Wait For" variation in my example code is the same one that you suggested, so I guess, as you mention, the event is called before the method is finished.
 
Last edited:

Informatix

Expert
Licensed User
I first tried getting it to work with this one (see end of thread):

https://www.b4x.com/android/forum/threads/sd-ziplibrary.90733/

Then I tried getting it to work with this one:

https://www.b4x.com/android/forum/threads/lib-archiver.21688/

I don't like having a bunch of async subs jumping execution all around the place - hard to read and maintain. So, that's why I want to use Wait For because it keeps code flow clear and contained.

I must be doing something wrong because this is the second ZIP lib I am trying to get working with "Wait For" without any success.

I tried all FOUR "wait for" lines below and the code just hangs on them (obviously I tried them one at a time ;):
(This code is in a sub within the Main Activity)
B4X:
'export app settings
Dim Zip As ArchiverPlusZip
Dim SF As List
SF.Initialize
SF.Add(File.Combine(File1Dir,"mydatabase.db"))
SF.Add(File.Combine(File2Dir,"com.myapp_preferences.xml"))
Zip.AddFilesToZip(SF,File.Combine(ZipDir,"MyApp_Settings.zip"),"Zip")

Wait for ZipResult(Result As Int, ErrorMsg As String)
Wait for (Zip) ZipResult(Result As Int, ErrorMsg As String)
Wait for Zip_ZipResult(Result As Int, ErrorMsg As String)
Wait for (Zip) Zip_ZipResult(Result As Int, ErrorMsg As String)
You should take a look at the Performance example provided with the library:
B4X:
...
   Arc.ZipExecutionMode = Arc.ZIP_EXECMODE_ASYNCHRONOUS
   Arc.AddFolderToZip(ArchiveFolder & "zip", ArchiveFolder & "TestPerf_AsyncWF.zip", "ArchiverWF")
   Wait For ArchiverWF_ZipResult(Result As Int, ErrorMsg As String)
...
The default execution mode is SYNCHRONOUS.
In your code, "Wait For" will be run only when the AddFolderToZip task is done. You have to specify with ZipExecutionMode that you want to add these files in a background thread.
 

JohnC

Well-Known Member
Licensed User
You should take a look at the Performance example provided with the library:
B4X:
...
   Arc.ZipExecutionMode = Arc.ZIP_EXECMODE_ASYNCHRONOUS
   Arc.AddFolderToZip(ArchiveFolder & "zip", ArchiveFolder & "TestPerf_AsyncWF.zip", "ArchiverWF")
   Wait For ArchiverWF_ZipResult(Result As Int, ErrorMsg As String)
...
The default execution mode is SYNCHRONOUS.
In your code, "Wait For" will be run only when the AddFolderToZip task is done. You have to specify with ZipExecutionMode that you want to add these files in a background thread.
So I tried using your lib again by using the above code your provided and looking at the performance example, but as you can see in the below thread, it just seems like there is a major conflict between your lib (in sync or async mode) and using Wait For/MsgBoxAsync.

Any thoughts on how to fix this?

 

Informatix

Expert
Licensed User
So I tried using your lib again by using the above code your provided and looking at the performance example, but as you can see in the below thread, it just seems like there is a major conflict between your lib (in sync or async mode) and using Wait For/MsgBoxAsync.

Any thoughts on how to fix this?

The problem has nothing to do with my library but with your lack of knowledge of how multitasking works in Android. When a task runs in the background, which is the case when you set the asynchronous mode for ArchiverPlusZip, you cannot change the user interface directly (by changing a view property or displaying a dialog). You must call a sub with CallSubDelayed to make this change.
 

JohnC

Well-Known Member
Licensed User
The problem has nothing to do with my library but with your lack of knowledge of how multitasking works in Android. When a task runs in the background, which is the case when you set the asynchronous mode for ArchiverPlusZip, you cannot change the user interface directly (by changing a view property or displaying a dialog). You must call a sub with CallSubDelayed to make this change.
NOTE: Please don't take any of my posts as confrontational in any way. I am just confused and want to understand exactly what the issue is so I can be confident that when I release an app using this code, it will run reliably.

But even when I try using it in the default SYNCRONOUS mode (so then it is NOT running in the background?) and use the below separate event sub, it will still crash if I try to display a msgboxasync in the event sub:

B4X:
Sub zip_ZipResult(Result As Int, ErrorMsg As String)

    If Result <> Zip.ZIP_RESULT_SUCCESS Then
        MsgboxAsync("There was an Error creating the ZIP file (" & ErrorMsg & ")","Zip Error")
    Else
        MsgboxAsync("ZIP file created ok!","Zip")
    End If

End Sub
You're right, I don't know much about the innards of android multitasking, but I can sort of understand when you say that if I set it to ASYNCHRONOUS mode, the zip operation is running in another task (for performance reasons) so that my app can do other things, and until the background zip task finishes, I can't update the UI due to the multitasking. OK, that makes sense I guess.

But if I direct your lib to work in SYNCHRONOUS mode, why is it still triggering the ZipResult event when it appears a background zip operation/task is still running (because it will crash if I try to update the UI in the event sub)?

So, when I configure it for SYNCHRONOUS mode, why can't the event wait until the zip operation/task is actually fully completed (and accordingly the background task is fully finished) before it triggers so I can change the UI with it crashing?

Basically, if I can't update the UI because there is a background task running, then why doesn't SYNCHRONOUS mode fix this problem by not invoking the event until after the background task is fully complete so it wont interfere with the UI thread anymore?

And lets say I want to email the zip file right after the Zip operation, do I still need to do a CallSubDelayed(Me, "Send-Email") to make sure the zip file is fully ready to be emailed and will not cause an error because the email program wasn't able to properly attach it to the email because the zip file was still open by the background zip task?

And is the CallSubDelayed solution 100% guaranteed to only run after the zip operation is fully completed even for a large zip operation?
 
Last edited:

Informatix

Expert
Licensed User
But if I direct your lib to work in SYNCHRONOUS mode, why is it still triggering the ZipResult event when it appears a background zip operation/task is still running (because it will crash if I try to update the UI in the event sub)?
Doing long operations on files with a real synchronous mode is totally inadvisable under Android. That's why the Synchronous mode is actually an asynchronous mode, but it's the library that waits for the end of operations and not your code. This avoids the "application not responding" error message that occurs when the main thread is blocked.

Basically, if I can't update the UI because there is a background task running, ...
You can still update the UI but not from the event sub. You have to call another sub with CallSubDelayed.

And is the CallSubDelayed solution 100% guaranteed to only run after the zip operation is fully completed even for a large zip operation?
Yes, it's THE solution, not a workaround.
I really regret that you didn't even try it. It would have avoided unnecessary tension.
On my side, as Erel pointed out, I should have added documentation with the library that explains all this.
 

JohnC

Well-Known Member
Licensed User
Ok, thank you for those details.

I did try the CallSubDelayed and it did fix the crashing when changing the UI :)

However, I still have one last question on when the ZIP operation is fully completed...

In doing tests, it seems the "zip_ZipResult" event sub will trigger no matter if I run it in "SYNCHRONOUS" or "ASYNCHRONOUS" mode.

So, is it 100% guaranteed (in EITHER MODE) that the zip operation is fully complete when this event sub triggers? Meaning, can I run non-UI code in the event sub that will act upon the generated zip file (like copy/move/email) or is there even a slight chance that the background zip task might still be accessing the zip file while in the event sub?
 

Informatix

Expert
Licensed User
So, is it 100% guaranteed (in EITHER MODE) that the zip operation is fully complete when this event sub triggers? Meaning, can I run non-UI code in the event sub that will act upon the generated zip file (like copy/move/email) or is there even a slight chance that the background zip task might still be accessing the zip file while in the event sub?
The ZipResult event is triggered when the operation is a success, when it fails or when it is cancelled. In any case, in the library, there's nothing to run after it.
All operations are done in the background, but they are all executed in the same thread, one after the other. Therefore, no file operation can run in parallel with another.
 

JohnC

Well-Known Member
Licensed User
Thank you for talking the time to detail your answer :)
 

JohnC

Well-Known Member
Licensed User
I do have (hopefully) two last quick questions...

1) Can I use a MsgBoxAsync BEFORE I start a ZIP operation in the same sub (Async or Sync mode). Meaning, by having the msgboxasync in the sub, it will turn it into a resumable sub. So, I know its not good to change the UI while your ZIP is running, but is it ok to have a msgboxasync BEFORE I initiate a zip operation in the same sub?

2) What exactly is the difference between your ASYNCHRONOUS and SYNCHRONOUS mode, since even the SYNCHRONOUS runs a background task? Can you give me a few examples of when I would use one mode over the other?
 

Informatix

Expert
Licensed User
I do have (hopefully) two last quick questions...

1) Can I use a MsgBoxAsync BEFORE I start a ZIP operation in the same sub (Async or Sync mode). Meaning, by having the msgboxasync in the sub, it will turn it into a resumable sub. So, I know its not good to change the UI while your ZIP is running, but is it ok to have a msgboxasync BEFORE I initiate a zip operation in the same sub?

2) What exactly is the difference between your ASYNCHRONOUS and SYNCHRONOUS mode, since even the SYNCHRONOUS runs a background task? Can you give me a few examples of when I would use one mode over the other?
1) The problem you encountered is with the ZipResult event running in another thread. The other subs in your program are working normally.

2) From the library documentation (Functions and properties.html):
ZipExecutionMode As Byte
Gets or sets the execution mode of zip/unzip tasks (one of the ZIP_EXECMODE_ constants).
SYNCHRONOUS: waits for the end of the task (default mode).
ASYNCHRONOUS: does not wait for the end of the task. The function returns immediately and the task continues in the background. Check ZipResultCode to know whether the task has ended.
In both modes, do not try to handle views directly from within the events.
 

JohnC

Well-Known Member
Licensed User
2) From the library documentation (Functions and properties.html):
That's were I am confused...

It seems the Zip_ZipResult event will trigger in both Async and Sync modes, and you said once this event triggers, it's guaranteed the zip operation has completed (or errored). So I totally understand that now - thank you.

But in the below code:
B4X:
Arc.AddFolderToZip(ArchiveFolder & "zip", ArchiveFolder & "TestPerf_AsyncWF.zip", "ArchiverWF")

Log("After Zip Start")
1) Are you saying that in SYNC mode, the "Log" line will NOT execute until the zip operation is FULLY complete? ("waits for the end of the task" ie. is blocking execution)

2) And in Async mode, the Log line will run right away (even if the zip operation is NOT complete), and that I need to keep checking the .ZipResultCode properly in a do/loop to know when the operation has completed?
 
Last edited:

Informatix

Expert
Licensed User
That's were I am confused...

It seems the Zip_ZipResult event will trigger in both Async and Sync modes, and you said once this event triggers, it's guaranteed the zip operation has completed (or errored). So I totally understand that now - thank you.

But in the below code:
B4X:
Arc.AddFolderToZip(ArchiveFolder & "zip", ArchiveFolder & "TestPerf_AsyncWF.zip", "ArchiverWF")

Log("After Zip Start")
1) Are you saying that in SYNC mode, the "Log" line will NOT execute until the zip operation is FULLY complete? ("waits for the end of the task" ie. is blocking execution)

2) And in Async mode, the Log line will run right away (even if the zip operation is NOT complete), and that I need to keep checking the .ZipResultCode properly in a do/loop to know when the operation has completed?
1) Yes.
2) And yes.
 
Top