Firstly, may i request a way to create a Slider without a text box (or is there a way i’ve missed!). Currently you create the text box and then `setTexTboxStyle(Slider::NoTextBox …). This has the effect of deleting the default one.
Why does this matter?
Because setting things up and changing things are two different situations. When you create things, you’re just initialising but when you change, you’re sending out change notifications, repaints, etc.
Ok, in order to assist app start up, i do much of my initialisation in a background thread. I’ve discovered that i can create almost all my UI in a background thread on startup providing none of it is attached to the main window during this time.
so, thread creates everything. thread posts “i’m done”, main UI performs `MainWindow::setContentOwned’. works a treat! While this thread is in progress, the main UI can show a splash screen or even make a very simple UI to entertain the user.
Everything works fab except the Slider. changing the style to “NoTextBox” causes a the old Label to be deleted and ~AsyncUpdater gets upset:
// You're deleting this object with a background thread while there's an update
// pending on the main event thread - that's pretty dodgy threading, as the callback could
// happen after this destructor has finished. You should either use a MessageManagerLock while
// deleting this object, or find some other way to avoid such a race condition.
jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager());
It’s correct actually. i don’t want to be going around updating things not on the main UI. However, this is not what i’m really doing here. ie changing. it’d prefer a way to simply create once as i want it.
I just timed it again. it takes 5 seconds before the splash screen appears. about 4 of these are the OS itself launching. Then i take 10 more seconds in the background thread loading assets and creating the UI. Total is now about 15, down from over 20.
On the iPhone, the first non-splash UI needs to have lots of artwork, funky music and animating buttons - with sound effects. Otherwise people think it sucks.
I have to load and prep the sound system, decompress images and create the UI. Juce and iOS make heavy use of floating point and i have a 433Mhz embedded ARM. 15 seconds overall isn’t too bad, some apps i’ve tried take over 30 to start properly.
It’s important to show something as quick as possible. I know the faster devices will be a lot quicker, but even then, the quicker you can show some UI, the better the app.
Ah well that’s a different story. Its not the creation of Components that is taking the time, its the loading of your assets. Create the Components on the main thread and load the assets in the separate thread then.
But you have to show something so load the minimum of what you need to look good on launch and load the rest in the background.
Then i take 10 more seconds in the background thread loading assets and creating the UI.
Hmm, that’s still a very long time to create a UI!
I believe that the asset loading during that startup period is the bottleneck.
IMHO, a better way to do it is to create the actual GUI objects in a high-priority thread without any asset loading, and load all the assets in a single, lower priority thread. This means that you can start displaying something almost immediately and the GUI objects will refine as their assets are loaded. You can order the assets in your background thread in exactly the order you think most important for the user; you can delay actually displaying the GUI until “enough” assets are loaded with just a single shared flag; and careful choices of background colors and initial dimensions for your GUI elements to be similar to the assets that they’ll eventually load can dramatically reduce the visual effect of the actual assets being loaded a little later.
If loading time is still an issue and you have a large number of small images, you should look into “sprites” - that is, putting all your images into one big file and then displaying small portions of that file for individual images. Here’s a good article describing how to do that for CSS - the code is Juce is different but the technique exactly the same.
Oh, and this would probably fix your threading issue as well, because your UI creation would probably return to the main thread, and it’d be your asset loading only that lived in a separate thread.
I could do it the way you describe: I’d have an asset loader that loaded all the stuff. this would be in the background. it would signal the main thread on completion, which would (quickly) transfer all these to the relevant components.
The problem is that it gets very messy. This “loader” would have to know exactly everything to be loaded and to know which component needed what. or, more precisely, the main thread would have to create the UI components and fetch from the loader the relevant assets and put them in the right places. Each time i write a new component, i’d have to mess with this loader. The code for the component wouldn’t be complete without the loader.
Actually, i do this already, but within the scope of a specific component. This happens during the app normal running. The component used a thread to load upcoming assets. This is fine because it’s all tied up inside one component’s implementation.
This is not a good idea across multiple components. What are components anyhow. really, until they have a heavyweight peer, they are just classes that host their properties and assets. This is exactly where all the relevant loading and initialisation code should live.
I think it’s a good idea to be able to create a bunch of components together with all their required bits outside the UI thread in readiness for use.
Once the components are assigned a heavweight peer, such as being added to the UI display tree, then we’re in a different world; now they are windows or panels or UI or whatever.
I think it would suck if there was no way to ever create components except on the UI thread (or one that locks it).
I understand what you’re saying, but basically on these iOS apps, you pretty much need to load everything you can up front. This basically means the assets for the whole UI. Supposing you have several windows and most surfaces are covered with imagery, then you have a reasonable amount of assets to load.
this is where your 10 seconds goes on slow HW.
If you try to load stuff in the background at times when the user expects a fast tap response, you get a stutter.
You guys are all forgetting we’re dealing with much much slower hardware than you’re used to on desktops.
Damn - 10 seconds is a helluva long time for loading all this stuff! That seems painful enough that I can’t blame the OS for killing the app after 20 seconds of still constructing it, tbh. (Look at it as a crude version of quality assurance.)
Sprite sheeting is an important optimization; likewise, simply combining assets together to minimize the total amount. Must not forget that selectively lowering quality (therefore reducing space an asset may take) would be a good option to look at (ie: 24-bit audio to 16-bit, 48 kHz audio to 44.1 kHz, 3 minute background music loop in WAV versus a 1 minute long version in OGG). Doing that would give a considerable amount of memory headroom!
Also noteworthy, although captain obvious-like; loading only what you need when you need it.
jrlanglois: I agree with all your suggestions, except:
loading only what you need when you need it.
That really doesn’t work for UI applications, particularly mobile UI applications. Every operation has to “execute” as fast as possible - the controls need to feel fast even if there is some delay before operations are actually completed, and that means you need to have the next assets loaded before you need them.
I can suggest a sneaky hack if you want to avoid that background thread… Assuming that nothing is actually happening on the screen while all this is going on, you could just make occasional calls to MessageManager::runDispatchLoopUntil (1) in between loading assets, so that the event loop doesn’t seem to be frozen. Call that a few times a second and the OS should be kept happy.
But going back to your original post, it is a bit wasteful for the Slider to create a text editor and then delete it if you don’t want one - it might be a good idea for me to add another constructor that gives more immediate control over it.
I took the idea from your ThreadQueue and incorporated the whole show into a loader class i’m calling `BGLoader’. Like this, you don’t need any binding templates.
So, what you do is create your initial UI (eg splash), then start creating your main UI on the main thread, except that your components perform load requests, which all queue up and are processed by a background thread.
here’s one of my components,
[code]class Fatty: public Component
void paint(Graphics& g)
for (int i = 0; i < 10; ++i)
when you’re done posting loads, your main thread posts a final request indicating a main thread function to continue.
// first show splash
s = new Splash();
// fatty will use loader
f = new Fatty;
// post done message to continue to `go'
// here we go!
// switch over to fatty!
complete project attached. see bgloader.h for the action.