Skip to content
This repository has been archived by the owner on May 27, 2021. It is now read-only.

Optimizing LML

MJ edited this page Oct 8, 2016 · 3 revisions

This section contains a few tips on how you can make your GUI building slightly faster. LML is already rather quick and you mostly won't need these informations, but there are situations where you need LML to be blazing-fast (like on GWT, which has a rather slow reflection implementation), so this article might still be useful.

Prefer ActorConsumers to ActionContainers

ActorConsumer is a functional interface that consumes a single Actor (or other object, depending on its purpose) , does something (according to its implementation) and returns a single result. They might seem like an alternative to more convenient ActionContainers, which are scanned using reflection, but actually its the other way around: ActionContainer's methods are wrapped with ActorConsumer interface at runtime to unify the LML methods API.

By registering ActorConsumers directly, you omit the whole reflection scanning and invoking process. As you can guess, reflection-based actions are completely optional and were added on top of the regular, plain-old-Java mechanism. There's a drawback to this approach, though: unless using Java 8 lambdas or another JVM language, the syntax for creating new ActorConsumers is rather verbose. At least comparing to ActionConsumer, which is basically a class where every method can be invoked in LML.

Explicitly registered ActorConsumers are always preferred over ActionContainer methods in case of any name clashes, so you don't have to worry about the methods priority.

Use a single ActionContainer or explicitly reference container's IDs

If you still want to use reflection-based methods, you might want to make sure that method look-up is as fast as possible. When faced with a method reference (for example, action), LML parser will search through all ActionConsumers until it finds matching method with the selected name. By using a single ActionContainer or explicitly referencing a specific container (for example, global.action), you limit the time that LML parser spends scanning through ActionContainers with reflection.

Keep Lml#EXTRACT_FIELDS_AS_METHODS as false

Being able to extract field values from ActionContainers in LML is very convenient, but this functionality prolongs the time needed to scan through an ActionContainer (see previous point) and is very error-prone on GWT.

Prefer custom macros over imports

Importing external templates requires LML parser to load an additional file each time it is referenced. Files are not cached to limit meta-data kept by the parser at runtime. On contrary, custom macros need to be parsed once and then they are kept by the parser: you can use custom macros defined with <:macro> tag in any template, not only the one it was created in.

Prefer style sheets over custom macros

As a rule of thumb: if you wrap a single actor with a macro, consider if a set of the default attributes would be enough to set it up. If yes, do not use macros. Style sheets page explains why default attributes are usually more convenient. Due to how macro mechanism works, using macros can basically double the amount of text that has to be processed by the parser.

Set Lml.DISABLE_COMPONENT_ACTORS_ATTRIBUTE_PARSING to true

If this setting is true, component actors cannot have additional attributes. For example, normally you can use Label attributes (like labelAlign) in a Window - they will modify Label instance used as its title. However, if this settings is change to true, component actors will no longer be processed and cannot have their specific attributes - so, for example, using Label attributes in a Window tag would cause an exception. While it limits customization of some actors in LML, this speeds up attribute parsing of widgets that actually have component actors. A rule of thumb: if you set this value to true, try using a strict parser and see if your application is still running just fine; if it is, you should keep it that way.

Delete references to LmlParser after creating all views

This one is pretty obvious, but not always possible or convenient. If you created all views and you're 100% sure you're not going to use LML to parse any more actors, you can delete all references to LML parser. This will most likely schedule it to be garbage-collected. Note that usually the memory footprint isn't nearly big enough to care.

Use LmlUtilities#clearLmlUserObject or LmlUtilities#clearLmlUserObjects

This will clear user objects (see Actor#setUserObject) recursively. LML exploits user object mechanism to store various meta-data, including Table's Cells, Tree's Nodes, and additional settings that are unavailable in vanilla Scene2D. Again, memory footprint shouldn't be that big - and some meta-data is useful even at runtime, like stage attachers - but if you invoke these methods on your actors after adding them to Stage and nothing crashes, you can just leave it that way and enjoy having less objects at runtime. Just don't come running with new bug issues, because you have been warned.

Set Lml#EXTRACT_UNANNOTATED_METHODS to false

When this setting is turned on (the default), LML will go through all methods of your registered ActionContainer instances, even if they are not annotated with @LmlAction. This can significantly influence action lookup time.