Stulish Active Member Licensed User Longtime User Jul 21, 2015 #1 Hi i have a B4J app that unzips multiple files, and i wanted to show the progress but the indicator doesn't update until the end Code: Copy Private selection_progress_ind as ProgressIndicator Sub OpenZipGetFile(fn as string,perc as double) selection_progress_ind.visible = true selection_progress_ind.progress = (perc/100) If File.Existis(File.GetFileParent(fn),File.GetName(fn)) Then Zip.ABUnzip(fn,tempDir) Else Log("No File: " & fn) End If End Sub The Selection_Progress_ind is added in designer so i didn't initialize, and the sub OpenZipGetFile is called for a for next loop that runs through all the files selected. The Progress Indicator remains empty until all of the files have been unzipped and then reports 100%. Any help is appreciated. Regards Stu
Hi i have a B4J app that unzips multiple files, and i wanted to show the progress but the indicator doesn't update until the end Code: Copy Private selection_progress_ind as ProgressIndicator Sub OpenZipGetFile(fn as string,perc as double) selection_progress_ind.visible = true selection_progress_ind.progress = (perc/100) If File.Existis(File.GetFileParent(fn),File.GetName(fn)) Then Zip.ABUnzip(fn,tempDir) Else Log("No File: " & fn) End If End Sub The Selection_Progress_ind is added in designer so i didn't initialize, and the sub OpenZipGetFile is called for a for next loop that runs through all the files selected. The Progress Indicator remains empty until all of the files have been unzipped and then reports 100%. Any help is appreciated. Regards Stu
R Roycefer Well-Known Member Licensed User Longtime User Jul 21, 2015 #2 The unzipping should be performed off the main thread if you hope to be able to execute UI changes concurrently. UI changes are sent to the end of the message queue on the main thread so they won't execute until the main thread can process messages. If the main thread is bogged down unzipping files, then the UI won't be updated until it's finished doing all that. At that point, all your calls to update the ProgressBar will be executed in rapid succession and you won't be able to see the progress. It'll look like it just snaps to 100%. From your unzipping thread, call unzipThread.RunOnGuiThread("progressUpdater", Array(d)) where progressUpdater is a method (that accepts an Object as a parameter which you will cast to a Double inside the method) that updates the ProgressBar. Also, make sure that your unzipThread doesn't send too many requests to update the UI too close together or else the UI will update in a jerky, unsmooth manner (or not at all). If the updating is too jerky, keep track of how long ago, in milliseconds, the last update request was sent by the unzipThread and only send another request if the last request was more than 33 milliseconds ago. This amounts to a ProgressBar refresh rate of 30 frames per second. Any faster and the human brain can't really tell the difference and you're just bogging down the UI thread for no added benefit. Upvote 0
The unzipping should be performed off the main thread if you hope to be able to execute UI changes concurrently. UI changes are sent to the end of the message queue on the main thread so they won't execute until the main thread can process messages. If the main thread is bogged down unzipping files, then the UI won't be updated until it's finished doing all that. At that point, all your calls to update the ProgressBar will be executed in rapid succession and you won't be able to see the progress. It'll look like it just snaps to 100%. From your unzipping thread, call unzipThread.RunOnGuiThread("progressUpdater", Array(d)) where progressUpdater is a method (that accepts an Object as a parameter which you will cast to a Double inside the method) that updates the ProgressBar. Also, make sure that your unzipThread doesn't send too many requests to update the UI too close together or else the UI will update in a jerky, unsmooth manner (or not at all). If the updating is too jerky, keep track of how long ago, in milliseconds, the last update request was sent by the unzipThread and only send another request if the last request was more than 33 milliseconds ago. This amounts to a ProgressBar refresh rate of 30 frames per second. Any faster and the human brain can't really tell the difference and you're just bogging down the UI thread for no added benefit.
Stulish Active Member Licensed User Longtime User Jul 21, 2015 #3 Thanks Roycefer, you are correct i didn't do the unzipping on another thread, i will look at creating another thread for this and try out what you have said. Thanks Stu Upvote 0
Thanks Roycefer, you are correct i didn't do the unzipping on another thread, i will look at creating another thread for this and try out what you have said. Thanks Stu
Erel B4X founder Staff member Licensed User Longtime User Jul 22, 2015 #4 You can use the Informatix Archiver library (from B4A). It supports asynchronous operations. Upvote 0
Stulish Active Member Licensed User Longtime User Jul 22, 2015 #5 Erel, Thanks for the help, i used the asyncunzip function, i can see the progress value in the Logs as i output to log before chganging the progress indicator, bu the indicator remains at 0 until the end then jumps to 100%. is it usual for the value to be output to the log but not update the ui?? thanks Upvote 0
Erel, Thanks for the help, i used the asyncunzip function, i can see the progress value in the Logs as i output to log before chganging the progress indicator, bu the indicator remains at 0 until the end then jumps to 100%. is it usual for the value to be output to the log but not update the ui?? thanks
R Roycefer Well-Known Member Licensed User Longtime User Jul 22, 2015 #6 Are you sending off all the unzip jobs to be performed one immediately after the other, without waiting for completion? Or are you waiting for one to complete before starting the next (this is my recommendation)? The _UnZipProgression and _UnZipDone events execute in the main thread (even if the actual unzipping is done off the main thread) which means all the stuff I said about message queues and main threads in my previous post still applies. If you have 10 _UnZipProgressions arriving in the main thread message queue in rapid succession (i.e. #10 arrives before #1 has returned) and each one updates the ProgressBar, each one will be sending a message to update the ProgressBar to the end of the message queue. Which means the PB won't be updated until all those 10 events have returned and then all the PB update messages will be executed in rapid succession. The bottom line is you have to be aware of how fast you're crowding up the message queue in the main thread and design your algorithm to avoid overcrowding if you want the UI to update smoothly. Upvote 0
Are you sending off all the unzip jobs to be performed one immediately after the other, without waiting for completion? Or are you waiting for one to complete before starting the next (this is my recommendation)? The _UnZipProgression and _UnZipDone events execute in the main thread (even if the actual unzipping is done off the main thread) which means all the stuff I said about message queues and main threads in my previous post still applies. If you have 10 _UnZipProgressions arriving in the main thread message queue in rapid succession (i.e. #10 arrives before #1 has returned) and each one updates the ProgressBar, each one will be sending a message to update the ProgressBar to the end of the message queue. Which means the PB won't be updated until all those 10 events have returned and then all the PB update messages will be executed in rapid succession. The bottom line is you have to be aware of how fast you're crowding up the message queue in the main thread and design your algorithm to avoid overcrowding if you want the UI to update smoothly.
Erel B4X founder Staff member Licensed User Longtime User Jul 22, 2015 #7 You need to handle the UnzipProgression event: https://www.b4x.com/android/help/archiver.html#archiver_asyncunzip Upvote 0
You need to handle the UnzipProgression event: https://www.b4x.com/android/help/archiver.html#archiver_asyncunzip
Stulish Active Member Licensed User Longtime User Jul 22, 2015 #8 Hi Erel, Thanks for your fast responses as always, My problem is each zip file only holds one file, so i loop through each selected file to unzip, i can see the log fill up with 'Progress: ???' as it unzips each file, but the progress of the progress indicator is not updated. Code: Copy Sub UnzipSelected() For a=startindex to stopindex Dim tempName as String = SortedList.get(a) OpenZipGetFile(tempName) selection_progress_ind.Progress = (a/stopindex) Log("Progress: " & (a/stopindex)) Next End Sub Code: Copy Sub OpenZipGetFile(fn as string,perc as double) If File.Existis(File.GetFileParent(fn),File.GetName(fn)) Then Zip.asyncunzip(file.GetFileParent(fn),File.GetName(fn),tempDir,"UnzipDone") Else Log("No File: " & fn) End If End Sub next i updated the UnzipProgression sub as follows Code: Copy Sub UnzipDone_UnzipProgression(Count as Int, FileName as String) selection_progress_ind.Progress = currentPlay Log("Done: " & currentPlay & ")") End Sub When i run the app, i can see the 'Progress: ??' and the 'Done: (??)' Log entries increasing with each file from 0 to 1 but the progress indicator only updates once all unzipping is complete? If i put a break point on the 'Log("Done: " & currentPlay & ")") line, the program doesn't pause until all unzipping is complete even though the log updates each entry from 0 to 1. So i am still stuck. Regards Stu Upvote 0
Hi Erel, Thanks for your fast responses as always, My problem is each zip file only holds one file, so i loop through each selected file to unzip, i can see the log fill up with 'Progress: ???' as it unzips each file, but the progress of the progress indicator is not updated. Code: Copy Sub UnzipSelected() For a=startindex to stopindex Dim tempName as String = SortedList.get(a) OpenZipGetFile(tempName) selection_progress_ind.Progress = (a/stopindex) Log("Progress: " & (a/stopindex)) Next End Sub Code: Copy Sub OpenZipGetFile(fn as string,perc as double) If File.Existis(File.GetFileParent(fn),File.GetName(fn)) Then Zip.asyncunzip(file.GetFileParent(fn),File.GetName(fn),tempDir,"UnzipDone") Else Log("No File: " & fn) End If End Sub next i updated the UnzipProgression sub as follows Code: Copy Sub UnzipDone_UnzipProgression(Count as Int, FileName as String) selection_progress_ind.Progress = currentPlay Log("Done: " & currentPlay & ")") End Sub When i run the app, i can see the 'Progress: ??' and the 'Done: (??)' Log entries increasing with each file from 0 to 1 but the progress indicator only updates once all unzipping is complete? If i put a break point on the 'Log("Done: " & currentPlay & ")") line, the program doesn't pause until all unzipping is complete even though the log updates each entry from 0 to 1. So i am still stuck. Regards Stu
Stulish Active Member Licensed User Longtime User Jul 22, 2015 #9 I have also changed the UnzipSelected Sub to use CallSubDelayed Code: Copy Sub UnzipSelected() For a=startindex to stopindex Dim tempName as String = SortedList.get(a) OpenZipGetFile(tempName) currentPlay = a/stopindex CallSubDelayed(Me,"updateProgress") Next End Sub Sub updateProgress selection_progress_ind.Progress = currentPlay Log("Progress: " & currentPlay) EndSub Still the update only happens at the end of every file to be zipped? Upvote 0
I have also changed the UnzipSelected Sub to use CallSubDelayed Code: Copy Sub UnzipSelected() For a=startindex to stopindex Dim tempName as String = SortedList.get(a) OpenZipGetFile(tempName) currentPlay = a/stopindex CallSubDelayed(Me,"updateProgress") Next End Sub Sub updateProgress selection_progress_ind.Progress = currentPlay Log("Progress: " & currentPlay) EndSub Still the update only happens at the end of every file to be zipped?
Stulish Active Member Licensed User Longtime User Jul 22, 2015 #10 Hi Roycefer, I have only just seen your reply in between Erels, i am sending one after another without waiting for a completed, i will look at waiting for the unzip complete before sending the next sip file and see if that works. Thanks Stu Upvote 0
Hi Roycefer, I have only just seen your reply in between Erels, i am sending one after another without waiting for a completed, i will look at waiting for the unzip complete before sending the next sip file and see if that works. Thanks Stu
rwblinn Well-Known Member Licensed User Longtime User Jul 22, 2015 #11 Hi, scribbled an example (only showing unzipping) using the Informatix Archiver library (great lib = thanks to Informatix). To note: The handling of multiple files in the example can be optimized, but its works. Attachments B4JHowToArchiverLib.zip B4JHowToArchiverLib.zip 45.1 KB · Views: 440 Upvote 0
Hi, scribbled an example (only showing unzipping) using the Informatix Archiver library (great lib = thanks to Informatix). To note: The handling of multiple files in the example can be optimized, but its works.
Stulish Active Member Licensed User Longtime User Jul 25, 2015 #12 Thanks rob, i will take a look once i get half an hour Upvote 0