Introducing the AsyncLoop class

 

Out of my recent work, I’m especially proud of and excited about the AsyncLoop class. It’s a serious performance enhancer that takes heavy processes and spreads them out over time, preventing stalls and possible lockups. I originally wrote it to deal with a for loop that contained a complex process and iterated 1000 times. Needless to say, the beach ball made an extended stay each time the loop ran. After implementing AsyncLoop, the beach ball disappeared and animations played smooth throughout.

AsyncLoop works around a timer limit. The developer sets the maximum number of milliseconds to loop through the process function. Once the timer exceeds that limit, it carries over to the next frame and repeats. The loop can be ended a number of ways, providing great flexibility. A limit can be placed on the loop count, mimicking common for loop usage. The loop can return the AsyncLoopAction.BREAK constant. When using that method, AsyncLoopAction.CONTINUE is used to tell the loop to continue to the next tick. Each loop provides analytics, keeping track of its duration, loop count, and frame count. Here are two ways you can use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// new AsyncLoop(callback:Function, countLimit:int = -1, timerLimit:int = 20);
var loop:AsyncLoop = new AsyncLoop(tick, 1000);
 
loop.addEventListener(Event.OPEN, loopOpenHandler);
loop.addEventListener(Event.CHANGE, loopChangeHandler);
loop.addEventListener(Event.COMPLETE, loopCompleteHandler);
 
loop.start();
 
function tick():void {
	// heavy process
}
 
function loopOpenHandler(event:Event):void {
	// loop started
}
function loopChangeHandler(event:Event):void {
	// loop carries over to next frame
 
	trace(loop.duration); // incomplete loop running time
	trace(loop.currentCount); // number of callback calls
}
function loopCompleteHandler(event:Event):void {
	// loop complete
 
	trace(loop.duration); // completed loop duration
	trace(loop.frameCount); // frames needed to complete
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var loop:AsyncLoop = new AsyncLoop(tick);
 
loop.start();
 
stage.addEventListener(MouseEvent.CLICK, clickHandler);
stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
 
function tick():String {
	// heavy process
 
	if (loopShouldEnd) {
		return AsyncLoopAction.BREAK;
	}
 
	return AsyncLoopAction.CONTINUE;
}
 
function clickHandler(event:MouseEvent):void {
	if (loop.running) {
		loop.pause();
	} else {
		loop.start();
	}
}
function doubleClickHandler(event:MouseEvent):void {
	loop.cancel();
}

I’m really happy with the class and how far it has come since its original form as fLoop. As always, the source code is on GitHub, so take it and run! If you find it useful, feel free to share how you used it, or simply let me know what you think.

Introducing the ApplicationUtil class

 

Yesterday, during my weekly football “service”, I spent a few minutes starting the ApplicationUtil class. So far, it consists of only two methods, getVersion and closeOpenWindows. The first accesses the application descriptor and returns the application’s version. closeOpenWindows is a necessity I learned in the Apollo days from Christian Cantrell. I had issues with my first AIR app, DestroyFlickr, where it wouldn’t quit, even if all of the visible windows were closed. I commonly use window visibility to show/hide utility windows, so the invisible ones were hanging around, keeping the app open. This method runs a quick loop to close all open windows, visible or not. It also includes an andQuit argument that, when true, sets autoExit to true, which quits the app upon close of the windows. Here’s some unnecessary example code to give this post more character:

1
2
3
4
5
6
7
8
9
10
var version:String = ApplicationUtil.getVersion();
trace(version); // v1
 
trace(NativeApplication.nativeApplication.openedWindows.length); // 3
ApplicationUtil.closeOpenWindows();
trace(NativeApplication.nativeApplication.openedWindows.length); // 0
 
// suppose three windows are open again
ApplicationUtil.closeOpenWindows(true); // closes windows and quits before trace is called
trace(NativeApplication.nativeApplication.openedWindows.length);

Introducing the Scale9Bitmap class

 

scale9bitmap

The Scale9Bitmap class applies a scale9Grid to a Bitmap. It takes advantage of a technique I used for DestroyTwitter’s window drop shadow, scaling nine Bitmap instances. When developing the MAX Companion, I tried Didier Brun’s ScaleBitmap class, but discovered a costly memory leak in which it instantiates a new BitmapData instance with every resize call. This wouldn’t be a big deal for a once-and-done resize, but as a window drop shadow, memory skyrockets.

I decided to start from scratch and develop a class that is super fast and slim as can be. The Bitmaps are only updated when the BitmapData is set. After that, the only process that takes place is the resizing of each Bitmap—no BitmapData manipulation needed. Setup requires a single method to set the BitmapData and the Rectangle that indicates the stretchable portion of the Bitmap. BitmapData can be changed on the fly and there is a scale property that sets both scaleX and scaleY.

The source code is on GitHub, so feel free to give it a whirl.

Two feet of snow and the Canon 50mm f/1.2L

 

Jen in the snow

Yesterday, Jen asked if we would still be able to go out today because of the snow forecast. I said, “I don’t see why not. It’s probably going to flurry.” Two feet of snow later, we decided to take the camera out for a walk. It was a lot colder than expected, so we didn’t stay out very long. At f/2.8 with my new 50mm f/1.2, I was able to snag a few beauties of Jen.

A trip down memory lane

 

In high school, a few friends and I played a game during study hall. We called it Flips. The game combined handball, hacky sack, and horse. We used a paper ball wrapped in tape and hit it between each other with our hands. If a player faults, they earn a letter. Once a player spells “Flips,” they are out of the game. A fault occurs if a player hits the ceiling with the ball, hits the ball out of bounds, hits a malicious ball, or is unable to return the ball. The last two players in the game go one on one in a “championship”. Whoever survives wins and a tally is added to their score. We easily surpassed 300 games throughout the year.

Senior year, I took a film course. Flips was a year-long production and my submission for the class’s film festival. We filmed all year just so we would be able to play. A number of the people involved were simply given a job to get out of study hall. After the film festival, the hall monitors were onto us and reported us to the principal. Through some smooth talking, we were given permission to play and even got to play in the principal’s office! I can easily say Flips made me wake up in the morning and want to go to school.

Here, in its entirety, is the Flips documentary:

Taking a break from DestroyTwitter

 

It has been exactly one year since I decided to enter the Twitter app world with DestroyTwitter. Within this year, there has been 45 public releases and over 300,000 installs. After working tirelessly on it, all the while juggling college and a job, it’s time to take a break. As much as I love developing DestroyTwitter, I want to experience a life away from the computer for those hours after 5 pm.

Anyone who knows me has probably seen me in front of a computer more often than not. And with every year that goes by, I feel one step closer to burning out. I want to be able to code for as long as I can, but I know it isn’t healthy to maintain my current pace. In college, the morning/day/night work schedule made sense—I was surrounded by peers who worked around the clock as well. Now that I have a full-time job and a family, it’s time to balance the work with a period of downtime and recreation.

I will continue to respond to emails regarding DestroyTwitter as best I can, but I have no plans to post the source code. If you have any questions, feel free to ask them in the comments. It has been a fun year and I can’t thank you enough for contributing to the project.

Introducing the Console class and debug package

 

I realized I need a more…official…way of debugging my apps, so I wrote the Console class. It’s primary function is to record activity to a specified log file. So far, I have a few methods that write entries—success, error, cancel, and print. I definitely plan to add more, but these are the main ones I intend to use in the near future. Since the name “trace” is off limits in AS3, I referenced my PHP background and named the trace method, “print”.

The class also includes the ability to automatically trace entries to Eclipse’s console along with writing them to a file. Files are written asynchronously, but I also added a delay property that combines entries, so the writing process is less likely to slow down the app. Taking advantage of AIR 2.0’s UncaughtErrors feature, the Console automatically logs fatal errors and their stack traces, if possible. Here’s an example of its usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var path:String = File.applicationStorageDirectory.nativePath;
 
// params: log file path, LoaderInfo
// automatically writes a session start entry to the log
Console.init(path, loaderInfo);
 
Console.delay = 1000;
Console.traceError = true;
 
// params: id, message
Console.success("wp post", "wrote blog post");
 
// params: id, message
Console.error("wp post", "previous post was depressing");
 
// params: id, message
Console.cancel("Christmas", "why would you want to do that?");
 
// params: message
Console.print("this is a test");
[Fri Dec 18 00:31:31 GMT-0500 2009] Session Start
[Fri Dec 18 00:31:31 GMT-0500 2009] [success] [wp post] wrote blog post
[Fri Dec 18 00:31:31 GMT-0500 2009] [error] [wp post] previous post was depressing
[Fri Dec 18 00:31:31 GMT-0500 2009] [cancel] [Christmas] why would you want to do that?
[Fri Dec 18 00:31:31 GMT-0500 2009] [print] this is a test

I do expect to build the class over time, eventually adding TextField support. In the meantime, the source code is available on GitHub.

Outroducing Introducing the CurrentDate class

 

Always test, never assume. I was so caught up with how cool typing CurrentDate.time looks, I forgot to test the class for performance. Kristopher Schultz pointed out in the comments that instantiating a new Date instance is much faster than any method in the CurrentDate class. Taking it one step further, I tested it for memory and found similar results.

CurrentDate will be removed from DestroyFramework, but it will always have a place in my heart.

[note] I know “outroducing” is not a word, but it damn well should be.

I’m working on a debug package for DestroyFramework and found the need, in my Log class, to retrieve the current timestamp whenever entries are made. I looked through the almost laughably redundant Date class and found no methods for updating the instance to show the current date and time. Since I’m an avid recycler, there was no way I would instantiate a Date instance each call. Immediately, I thought of the getTimer method. Because it tallies the number of milliseconds since the SWF or AIR app starts, I should be able to add that to the Date.milliseconds property to return the current date. It worked!

1
2
3
4
5
var date:Date = new Date();
 
// delay a few seconds
 
date.milliseconds += getTimer();

Since I can’t assume a CurrentDate method will be called when getTimer() == 0, all I needed to do was include an offsetTimestamp variable that records getTimer when the Date instance is instantiated. I then subtract that variable from getTimer and I have the right number of milliseconds to update the Date instance with.

1
2
3
4
5
6
var offsetTimestamp:int = getTimer();
var date:Date = new Date();
 
// delay a few seconds
 
date.milliseconds += getTimer() - offsetTimestamp;

The class itself is as easy as pie to use. All of the methods are static, so you can simply call CurrentDate.time and it returns the Date.time property for the current time. I included every get and toString method found in Date. I also included two extra methods, antemeridian and postmeridian that indicate whether the current time is AM or PM. Since it can be formatted in different ways, I made the return values boolean.

1
2
3
4
5
6
CurrentDate.month; // 11 (months start at 0)
CurrentDate.date; // 15
CurrentDate.fullYear; // 2009
CurrentDate.toString(); // Tue Dec 15 8:13:08 GMT-0500 2009
CurrentDate.antemeridian; // true
CurrentDate.postmeridian; // false

As always, the source code for the new class can be found on GitHub.

Improved text handling in TextFieldPlus

 

This past week, I wrote a post regarding the sluggish TextField.text method. I also shared an alternative that shows incredible gains—storing the text prior to modifying it. I originally found it was 11 times faster, but after redoing the tests, I discovered that TextField.text’s speed is dependent on the number of characters in the String. Here are the results, including the new TextFieldPlus.text:

1 lorem ipsum paragraph (584 characters)
var text...........................42 / 0.071 msec/char (100,000 iterations)
TextFieldPlus.text.................63 / 0.107 msec/char (100,000 iterations)
TextField.text....................458 / 0.784 msec/char (100,000 iterations)
 
2 lorem ipsum paragraph (1,168 characters)
var text..........................42 / 0.035 msec/char (100,000 iterations)
TextFieldPlus.text................64 / 0.054 msec/char (100,000 iterations)
TextField.text...................1098 / 0.94 msec/char (100,000 iterations)
 
3 lorem ipsum paragraph (1,752 characters)
var text..........................42 / 0.023 msec/char (100,000 iterations)
TextFieldPlus.text................64 / 0.036 msec/char (100,000 iterations)
TextField.text..................2379 / 1.357 msec/char (100,000 iterations)

As you can see, the pre-stored method and TextFieldPlus.text maintain the same speed as the String grows, but TextField.text slows. TextFieldPlus.text uses the pre-stored method, but isn’t as fast because it’s a getter and includes a conditional to play nice with htmlText. Even so, the less work for the developer is worth the extra 20 milliseconds.

Along with TextField.text, I tackled TextField.text += String. This is even slower because it requires both getting and setting. It’s so slow, in fact, that the debugger displays a warning and suggests using TextField.append instead. This is considerably faster, but still slow.

To combat the speed issues, I developed a transaction-based system, inspired the SQLConnection class. With beginText and commitText, you can batch-modify a TextField’s text with either += or appendText. The latter is still faster, but by a slighter margin. Here are the speed results:

1,000 iterations
var text +=...............................................................1
TextField.text +=.......................................................620
TextField.append........................................................583
TextFieldPlus.text +=...................................................571
TextFieldPlus.appendText................................................578
TextFieldPlus.text += (transaction).......................................2
TextFieldPlus.appendText (transaction)....................................1
 
100,000 iterations
var text +=..............................................................53
TextField.text +=.................................................timed out
TextField.append..................................................timed out
TextFieldPlus.text +=.............................................timed out
TextFieldPlus.appendText..........................................timed out
TextFieldPlus.text += (transaction).....................................116
TextFieldPlus.appendText (transaction)...................................93

Just as before, TextFieldPlus’s methods are slightly slower, but the difference is worth it from a developer’s standpoint. While writing the new appendText method, I discovered a fun fact about TextField.appendText—the method actually calls TextField.replaceText(TextField.length, TextField.length, text). With this new knowledge, I figured I’d skip the middleman and call super.replaceText from appendText. Surprisingly, this is slower, so I stuck with super.appendText.

The updated source code is on GitHub, so TextFieldPlus is ready to go with the new implementation.

SpellCheckHighlighter class, demo app, and screencast

 

SpellCheckHighlighterDemo

This past week, I spent my spare time writing the SpellCheckHighlighter class. It allows non-Flex developers to use Adobe’s spellchecker, Squiggly, which only provides a UI for Flex components. Currently, SpellCheckHighlighter includes a number of additional settings like underline type and color. I’ve provided a screencast of the demo app below and the source code can be found on GitHub.

Please note, the volume on this screencast is a low because it was recorded at about 8 a.m. and everyone wasn’t awake yet.