views:

34

answers:

2

I've got an Adobe Flash 10 program that freezes in certain cases, however only when running under a release version of the flash player. With the debug version, the application works fine.

What are the best approaches to debugging such issues? I considered installing the release player on my computer and trying to set some kind of non-graphical method of output up (I guess there's some way to write a log file or similar?), however I see no way to have both the release and debug versions installed anyway :( .

EDIT: Ok I managed to replace my version of flash player with the release version, and no freeze...so what I know so far is:

Flash:     Debug   Release
Vista 32:  works   works
XP PRO 32: works*  freeze
  • I gave them the debug players I had to test this

Hmm, seeming less and less like an error in my code and more like a bug in the player (10.0.45.2 in all cases)... At the very least id like to see the callstack at the point it freezes. Is there some way to do that without requiring them to install various bits and pieces, e.g. by letting flash write out a log.txt or something with a "trace" like function I can insert in the code in question?

EDIT2: I just gave the swf to another person with XP 32bit, same results :(

EDIT3: Ok, through extensive use of flash.external.ExternalInterface.call("alert", "..."); I managed to find the exact line causing the problem (I also improved exception handling code so rather than freeze it told me there was an "unhandled" exception). The problem now is what on earth is flashes problem with this with the release player on some machines...

particles.push(p);

Which causes a TypeError #1034 on said platforms. Particles is a Vector.<Particle>, p is a Particle. I tested with getQualifiedClassName and got:

getQualifiedClassName(p) = ::Particle
getQualifiedClassName(particles) = _AS3_.vec::Vector.<::Particle>

Any ideas why this is a problem and what to do to make it work?

EDIT4:

Ok I seem to have solved this. The Particle class is just a simple internal class located after the package {...} in the action script file using it. I moved this into its own file (particle.as) and made it a proper public class in my package, and problem solved.

Maybe its a flash bug or maybe I missed the memo about not using internal classes in vectors or something, although if that's the case I would have expected something or other (either at compile time or with debug runtimes) to disallow it explicitly, e.g. some error on the "private var particles:Vector.<Particle>;" line. If I get a chance I guess I'll take a look at contacting the Adobe flash team concerning this or something.

Thanks for help giving debugging tips which I guess is more along the original questions lines :)

+1  A: 

Judging by when the freeze occurs, try to pinpoint some possibilities for what the offending code may be, and use De MonsterDebugger to check variables etc.

EDIT: I'm pretty certain that the actual call stack is only available to you in the debug versions of the Flash Player / AIR. Still, it may be useful in the debug player to trace the stack from within the handler for the button to see if anything is out of place:

var err:Error = new Error(“An Error”);
trace(err.getStackTrace());

FYI the getStackTrace method is only available in the debug player, so there is no way to write it to a log.txt in production.

Mark L
Well I know when it freezes in terms of what the user is doing with the app, its when a certain button is pressed, but I have no idea where in that code it freezes, and looking at the code I cant see any reason why it should do (all it is doing is creating some objects, setting a few variables and adding a new child to a Sprite while removing an old one), and basically all of that is code that has already run fine to get that far in the application... There is not even any loops in the code in question for it to get stuck in...
Fire Lancer
I'll have a look at that debugger. Will it be able to successfully grab information from a release version of the flash plugin, since obv on my machine with the debug version I have the Flash Builder debugger, but as I said it works fine there.
Fire Lancer
Yes it works with the release version of the plugin, though not as powerfully as the FB debugger. It can only work with properties that are exposed to the scope from which you initialize it.
Mark L
ok, so now i just need to figure out how to get a release version on my computer which currently has the debug versions?
Fire Lancer
When it freezes, do you get the "a script took too long" message? Or does it simply become unresponsive to further interaction? Does the CPU usage spike?
Mark L
hmm, will have to check, its hard right now since Im having to explain to someone else to do those things. Currently seeing if I can uninstall the debug versions in order to install the release version of the plugin and then hope I get the problem as well and its not effected by other factors (eg I'm on Vista, hes on XP)
Fire Lancer
What you can do is install the release version flash plugin for your browser, and it will not touch the debug player installed on your system, so you can still debug in Flash / FlashBuilder as per usual, and only use your browser for testing in production mode.I used to use the Flash Switcher plugin for Firefox when I needed to switch between versions 8 and 9 of the player, but it never quite worked for me when I switched to Mac. https://addons.mozilla.org/en-US/firefox/addon/5044/
Mark L
see edit. Ill check out the flash switcher here, although right now it seems whatever is causing this is not happening on my computer at all :(
Fire Lancer
updated the answer
Mark L
ok I found the source of the problem (see Edit3). Any ideas about what is going on their?
Fire Lancer
+1  A: 

This is a long shot, but are the Particles the objects that you are clicking? If so then catching the event in the wrong phase of bubbling, and pushing event.target (assuming it to be a Particle) could cause that problem.

Whatever the problem, I have something that should help you debug. A class that creates a pseudo trace window in your SWF, much nicer than extinterfacing to javascript. I've forgotten who wrote it, but I feel like it's Senocular. I use it any time I need to get traces back from end users.

Just drop it in the default package for your project, call stage.addChild(new Output());, and then to trace call Output.trace("A message");

package {
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.GradientType;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
    import flash.text.TextFieldAutoSize;

    /**
     * Creates a pseudo Output panel in a publish
     * swf for displaying trace statements.
     * For the output panel to capture trace 
     * statements, you must use Output.trace()
     * and add an instance to the stage:
     * stage.addChild(new Output());
     *
     */
    public class Output extends Sprite {
        private var output_txt:TextField;
        private var titleBar:Sprite;
        private static var instance:Output;
        private static var autoExpand:Boolean = false;
        private static var maxLength:int = 1000;

        public function Output(outputHeight:uint = 400){
            if (instance && instance.parent){
                instance.parent.removeChild(this);
            }

            instance = this;
            addChild(newOutputField(outputHeight));
            addChild(newTitleBar());

            addEventListener(Event.ADDED, added);
            addEventListener(Event.REMOVED, removed);
        }

        // public methods
        public static function trace(str:*):void {
            if (!instance) return;
            instance.output_txt.appendText(str+"\n");
            if (instance.output_txt.length > maxLength) {
                instance.output_txt.text = instance.output_txt.text.slice(-maxLength);
            }
            instance.output_txt.scrollV = instance.output_txt.maxScrollV;
            if (autoExpand && !instance.output_txt.visible) instance.toggleCollapse();
        }

        public static function clear():void {
            if (!instance) return;
            instance.output_txt.text = "";
        }

        private function newOutputField(outputHeight:uint):TextField {
            output_txt = new TextField();
            //output_txt.type = TextFieldType.INPUT;
            output_txt.border = true;
            output_txt.borderColor = 0;
            output_txt.background = true;
            output_txt.backgroundColor = 0xFFFFFF;
            output_txt.height = outputHeight;
            var format:TextFormat = output_txt.getTextFormat();
            format.font = "_sans";
            output_txt.setTextFormat(format);
            output_txt.defaultTextFormat = format;
            return output_txt;
        }

        private function newTitleBar():Sprite {
            var barGraphics:Shape = new Shape();
            barGraphics.name = "bar";
            var colors:Array = new Array(0xE0E0F0, 0xB0C0D0, 0xE0E0F0);
            var alphas:Array = new Array(1, 1, 1);
            var ratios:Array = new Array(0, 50, 255);
            var gradientMatrix:Matrix = new Matrix();
            gradientMatrix.createGradientBox(18, 18, Math.PI/2, 0, 0);
            barGraphics.graphics.lineStyle(0);
            barGraphics.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, gradientMatrix);
            barGraphics.graphics.drawRect(0, 0, 18, 18);

            var barLabel:TextField = new TextField();
            barLabel.autoSize = TextFieldAutoSize.LEFT;
            barLabel.selectable = false;
            barLabel.text = "Output";
            var format:TextFormat = barLabel.getTextFormat();
            format.font = "_sans";
            barLabel.setTextFormat(format);

            titleBar = new Sprite();
            titleBar.addChild(barGraphics);
            titleBar.addChild(barLabel);
            return titleBar;
        }

        // Event handlers
        private function added(evt:Event):void {
            stage.addEventListener(Event.RESIZE, fitToStage);
            titleBar.addEventListener(MouseEvent.CLICK, toggleCollapse);
            fitToStage();
            toggleCollapse();
        }

        private function removed(evt:Event):void {
            stage.removeEventListener(Event.RESIZE, fitToStage);
            titleBar.removeEventListener(MouseEvent.CLICK, toggleCollapse);
        }

        private function toggleCollapse(evt:Event = null):void {
            if (!instance) return;
            output_txt.visible = !output_txt.visible;
            fitToStage(evt);
        }

        private function fitToStage(evt:Event = null):void {
            if (!stage) return;
            output_txt.width = stage.stageWidth;
            output_txt.y = stage.stageHeight - output_txt.height;
            titleBar.y = (output_txt.visible) ? output_txt.y - titleBar.height : stage.stageHeight - titleBar.height;
            titleBar.getChildByName("bar").width = stage.stageWidth;
        }
    }
}
Mark L