Feathers MXML internals: abstracting away Starling initialization

Datetime:2016-08-23 02:57:02          Topic:          Share

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.