Yaron 53 Posted April 10, 2019 (edited) I actually posted this question on stack overflow a while back, got what I thought was a working answer but over time realized that on different devices, waiting for "onIdle" doesn't actually work. Here's the background, my app on first-load does some time-consuming (3-8 sec) pre-calculations so subsequent runs would be much faster. During this processing period, I want to show a "loading %" track-bar. However, for the life of me, I haven't been able to find the exact moment my form is visible and responsive for action. I tried different approaches: 1. waiting for "OnActivate" event. 2. Implementing IFMXApplicationEventService.SetApplicationEventHandler and waiting for "TApplicationEvent.BecameActive". 3. Waiting for "TApplicationEvent.BecameActive" to trigger and then waiting for 3 "OnIdle" events to trigger (2 OnIdle events were not enough for my Galaxy Note 4 device). Only #3 sort of worked on most devices using Delphi 10.2.3, but then when I upgraded to Delphi 10.3.1 even that stopped working (my progress bar shows up but the screen stops updating, so the bar remains on 0% until the pre-calculation function completes, even when calling Application.ProcessMessages after each update and no other code running in the background). Is there a better solution to know the exact moment my app will start responding to screen updates on launch under Android? Edited April 10, 2019 by Yaron Share this post Link to post
Микола Петрівський 10 Posted April 10, 2019 (edited) You are using Application.ProcessMessages, right? This is a well known feature of latest versions of FMX on Android. Details and workarounds are here: https://quality.embarcadero.com/browse/RSP-22888 Edited April 10, 2019 by Микола Петрівський Share this post Link to post
Yaron 53 Posted April 10, 2019 Just to make sure I understand, this implies I can't do UI updates in my main thread in the middle of a function? Share this post Link to post
Cristian Peța 103 Posted April 10, 2019 (edited) You can. But it will be drawn after the control is returned to UI. Edited April 10, 2019 by Cristian Peța Share this post Link to post
Remy Lebeau 1396 Posted April 10, 2019 (edited) 9 hours ago, Yaron said: I actually posted this question on stack overflow a while back, got what I thought was a working answer but over time realized that on different devices, waiting for "onIdle" doesn't actually work. The answer you were given on StackOverflow suggested you use a background thread, which is what you should be using. Quote Here's the background, my app on first-load does some time-consuming (3-8 sec) pre-calculations so subsequent runs would be much faster. During this processing period, I want to show a "loading %" track-bar. Start a background thread on app startup to perform your time-consuming work. Have the thread use TThread.Synchronize() or TThread.Queue(), or simply assign a handler to the TThread.OnTerminate event, to communicate back to the main thread when the background thread is finished. Have your UI display the trackbar by default, and then hide the trackbar when the background thread is finished. Quote However, for the life of me, I haven't been able to find the exact moment my form is visible and responsive for action. You don't need to in this situation. Quote I tried different approaches: 1. waiting for "OnActivate" event. 2. Implementing IFMXApplicationEventService.SetApplicationEventHandler and waiting for "TApplicationEvent.BecameActive". 3. Waiting for "TApplicationEvent.BecameActive" to trigger and then waiting for 3 "OnIdle" events to trigger (2 OnIdle events were not enough for my Galaxy Note 4 device). The OnIdle event is triggered whenever the main message loop receives a new message and then finishes processing all pending messages. Don't rely on the timing of that event to drive your app's logic. Quote Only #3 sort of worked on most devices using Delphi 10.2.3, but then when I upgraded to Delphi 10.3.1 even that stopped working (my progress bar shows up but the screen stops updating, so the bar remains on 0% until the pre-calculation function completes, even when calling Application.ProcessMessages after each update and no other code running in the background). Application.ProcessMessages() is broken in 10.3. You shouldn't be using it at all anyway. Do the pre-calculation in a background thread, and have the background thread post status updates to the main thread as needed. Let the main thread update the UI on its own schedule. Edited April 10, 2019 by Remy Lebeau 1 Share this post Link to post
Yaron 53 Posted April 11, 2019 Something weird happened in the post above, I can't edit it for some reason. I tried doing the pre-calculations in a thread, but it resulted in instability. what I'm doing is resizing graphic elements and I simply can't get TBitmap to work without throwing exceptions in a thread on Android. Share this post Link to post
Remy Lebeau 1396 Posted April 11, 2019 4 hours ago, Yaron said: tried doing the pre-calculations in a thread, but it resulted in instability. what I'm doing is resizing graphic elements and I simply can't get TBitmap to work without throwing exceptions in a thread on Android. TBitmap works in a thread, so you are probably just not using it correctly. But, if threading is not an option, then I suggest to break up your calculations into small chunks that you can execute asynchronously without blocking the UI thread, such as with TThread.ForceQueue(). Execute a chunk and queue the next chunk, then return to the main message loop. When ready, the next chunk will execute, queue the next chunk, return to the main message loop, and so on, until the calculations are finished. 1 Share this post Link to post
Микола Петрівський 10 Posted April 11, 2019 (edited) 10 hours ago, Yaron said: I tried doing the pre-calculations in a thread, but it resulted in instability. what I'm doing is resizing graphic elements and I simply can't get TBitmap to work without throwing exceptions in a thread on Android. As far, as I know, TBitmap had problems with threads in Tokyo. In Rio it should be fine. Edited April 11, 2019 by Микола Петрівський Share this post Link to post
Yaron 53 Posted April 11, 2019 The last time I suffered from TBitmap threading instability was in v10.2, so perhaps that's been resolved. Share this post Link to post
Remy Lebeau 1396 Posted April 12, 2019 (edited) On 4/11/2019 at 5:15 AM, Yaron said: The last time I suffered from TBitmap threading instability was in v10.2, so perhaps that's been resolved. Multi-threading issues for TBitmap were addressed in 10.2 Tokyo: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/What's_New#Multi-Threading_Support_for_TBitmap.2C_TCanvas_and_TContext3D Edited April 12, 2019 by Remy Lebeau Share this post Link to post
Yaron 53 Posted April 14, 2019 I was doing this in v10.2.3 and it was not stable, I chronicled my experiences here:https://stackoverflow.com/questions/52168940/is-png-decoding-not-thread-safe-under-android After replacing TBitmap PNG decoding with JBitmap, the issue was resolved, so I do believe that at least in v10.2.3 TBitmap is not thread safe. Share this post Link to post