Multi-window programming is something we’ve never had to worry about in Flash or Flex until now. AIR has a NativeWindow object which lets you write true multi-windowed desktop applications. Of course, along with additional power comes additional responsibility.
I just finished writing a screen saver application in AIR which I call SPF (Screen Protection Factor). It works basically like the picture viewer screen saver on OS X with the following features:
- It iterates through all the jpg, gif, and png files in a specified directory (and all sub directories).
- You can pick the transition interval (the amount of time each image is shown).
- You can set the idle interval (the amount of time that you have to be idle before the screen saver kicks in).
- It works with any number of monitors simultaneously.
I wrote a ScreenSaver class which extends NativeWindow, and when the user has been idle for the specified amount of time, I create a new ScreenSaver for each available monitor and show it at full screen. The ScreenSaver class has a timer which picks images at random and displays them at the full resolution of the monitor. When input is detected again (when the user is no longer idle), the code iterates through the collection of ScreenSaver instances and closes each one.
Pretty straightforward. Except for one thing.
Thanks to some debug trace statements, I discovered that after all the ScreenSaver instances were closed, their timers were still running and trying to display images. I figured one of two things was happening:
- I found a bug.
- The timers had references to the window, which were preventing them from being garbage collected.
Turns out I was wrong on both counts.
When you close a window and null out your references to it, you are making it eligible for GC, but that doesn’t mean it’s immediately GCed. It might be GC right away, or it might be around for another hour. It just so happens that we’re currently seeing unusually long intervals between collections on Mac right now (so to my credit, I did find partial bug, I guess), but regardless, AIR makes no guarantees of when your references are going to get cleaned up. That means you are still responsible for code that runs in those windows until they are finally reclaimed.
This should only be an issue for things like timers, or for asynchronous processes which might have been kicked off before the window was closed. If you working with any such code, be sure to listen for the closing event, and take care of any loose ends. Stop timers, and cancel all asynchronous processes that shouldn’t have a chance to return. If you’re extending NativeWindow, it’s as easy as adding an event listener to yourself, and adding a few lines of housekeeping code.
I will release SPF with the next public beta along with a few other fun apps I’ve been tinkering with.