Feathers MXML internals: abstracting away Starling initialization

In Starling projects, we need a startup class that extends flash.display.Sprite or flash.display.MovieClip. In this class, we create a starling.core.Starling instance, and we set up behavior for things like resizing the view port and pausing our app or game when it goes into the background. For many projects, this class looks mostly the same. When I create a new project, I usually just copy the startup class from an existing project and modify it to pass in a different Starling root class. It would be ideal if I could simply abstract this bootstrap code away instead.

Flex applications require a significant amount of bootstrapping code too. We don’t deal with any of it, though, because the Flex SDK compiler abstracts much of it away. We can simply create a simple MXML file extending spark.components.Application:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:s="library://ns.adobe.com/flex/spark">
</s:Application>

However, behind the scenes, a Flex SWF starts up with an mx.managers.SystemManager instance as the root display object. The spark.components.Application instance isn’t the root. It’s a child. Once the SWF fully loads and the Flex framework is ready, the SystemManager instantiates the Application and adds it to the display list.

You don’t need to worry about this bootstrapping code in Flex because the spark.components.Application class defines the following metadata:

[Frame(factoryClass="mx.managers.SystemManager")]

As long as you subclass Application this metadata will tell the compiler that your class should be included on the second frame of the SWF, and the class defined in the factoryClass should be the root display object instantiated when the SWF starts up. Once the first frame loads, the SystemManager can display a preloader while the second frame is loading. When the second frame is ready, the SystemManager instantiates the Application and adds it to the display list.

[Frame] metadata isn’t restricted to Flex applications. An ActionScript project built with the Flex SDK compiler may use [Frame] metadata too. In fact, some developers may have already used this metadata with Starling projects to create a preloader for SWFs that run in a web browser.

While it isn’t a strict requirement for supporting MXML in Feathers, I want the new project experience to be as simple Flex’s. We shouldn’t need to manually instantiate Starling and set up code to resize the view port and things. It should be part of some hidden bootstrap code. A new Feathers MXML application should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<feathers:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:feathers="library://ns.feathersui.com/mxml">
</feathers:Application>

The upcoming Feathers MXML SDK will include a feathers.core.Application class that takes advantage of [Frame] metadata.

package feathers.core
{
	import feathers.controls.LayoutGroup;

	[Frame(factoryClass="feathers.core.StarlingBootstrap")]

	public class Application extends LayoutGroup
	{
		public function Application()
		{
			super();
			this.autoSizeMode = LayoutGroup.AUTO_SIZE_MODE_STAGE;
		}
	}
}

All the bootstrapping happens behind the scenes in this feathers.core.StarlingBootstrap class, which serves a similar purpose as the Flex SystemManager. However, instead of initializing the Flex framework, it sets up Starling instead. It passes our subclass of feathers.core.Application to Starling to use as the root class. It listens for the native stage Event.RESIZE to resize the Starling view port and stage. It looks just like any normal startup class for a Starling project. Not much different than Starling’s Scaffold_Mobile sample or the Feathers ComponentsExplorer example.

The main difference between StarlingBootstrap and other startup classes is that StarlingBootstrap must have a method named info(). The compiler generates a subclass of StarlingBootstrap and overrides info() to make it return an object with a number of properties. This object stores things like the name of the Starling root class and, optionally, a Feathers theme. You can see a slightly simplified example of this generated subclass below:

public class _MyFeathersApp_feathers_core_StarlingBootstrap
	extends feathers.core.StarlingBootstrap
{
	public function _MyFeathersApp_feathers_core_StarlingBootstrap()
	{
		super();
	}

	private var _info:Object;

	override public function info():Object
	{
		if (!_info)
		{
			_info = {
				rootClassName: "MyFeathersApp",
				themeClassName: "feathers.themes.MetalWorksDesktopTheme"
			};
		}
		return _info;
	}
}

You can see that our main class was named MyFeathersApp. A string representation is stored in the rootClassName property returned by the info() function. StarlingBootstrap uses getDefinitionByName() to access the Class:

var rootClassName:String = info()["rootClassName"];
var rootClass:Class = Class(getDefinitionByName(rootClassName));

Once it has the Class reference, StarlingBootstrap can pass it to Starling to instantiate when Stage 3D is ready. The compiler will automatically ensure that MyFeathersApp is compiled into the SWF, even though it is not strictly imported here.

Anyone will be able to read the ActionScript code that gets generated by the Feathers MXML SDK compiler. Similar to the Flex SDK, we will be able to add the -keep compiler argument to include a folder of generated ActionScript files in the same place as the compiled SWF.

Additionally, using the StarlingBootstrap class to bootstrap a Feathers MXML application won’t be strictly required. Custom [Frame] metadata may be added to any subclass of feathers.core.Application that will override its default metadata. This will let us provide a different startup experience, if needed. We might want to customize the stage size to support contentScaleFactor, for instance. Ideally, the bootstrapping mechanism should provide acceptable defaults for most projects, while keeping things as flexible as possible for more advanced requirements.

About Josh Tynjala

Josh Tynjala is a frontend software developer, open source contributor, karaoke enthusiast, and he likes bowler hats. Josh develops Feathers UI, a user interface component library for creative apps, and he contributes to OpenFL. One of his side projects is Logic.ly, a digital logic circuit simulator for education. You should follow Josh on Mastodon.

Discussion

  1. Nick

    Hey Josh,
    Great start on abstracting to MXML … Feathers MXML would be a brilliant add-on and frankly I do think that you should go with crowd funding on this – within the RIA developers community, a GPU accelerated UI to replace the old buggy flex components (or amend them) would be a big deal and will help us all a lot when building business oriented apps. Please, go with kickstarter or similar – put down a 100k+ goal and add $20 to $1k options for funding – I am 100% sure that those of us serious about AIR development for mobile will get on board in a heartbeat – I myself am ready to pledge a $100 right away for this sort of project and would contribute with whatever I can to speed up the development process. So, single sponsor funding sounds ok, but it comes with string attached (I’m sure) which perhaps is more focused on the sponsor’s own agenda.
    Keep up the great work!
    Cheers:
    -Nick

Leave a Reply

Your email address will not be published. Required fields are marked *