Accessibility

Flex Article

 

Debugging Flex Applications with Flex Builder

James Polanco

www.macromedia.com

One of the most powerful features in Macromedia Flex Builder 1.0 is the integrated Flex application debugger. With the debugger, you can:

Overall, this article explains how to use Flex Builder debugging and to help track down those tricky issues that arise in application development.

Requirements

To complete this tutorial you will need to install the following software and files:

Macromedia Flex Builder


Managing Breakpoints

One of the central abilities in debugging applications is setting breakpoints for a specific line of ActionScript. A breakpoint is similar to setting a place for your Flex application to pause. By pausing the application, you can then view a snapshot of the application’s current state.

In Flex Builder there are several ways to manage breakpoints:

In the process of debugging a Flex application, you often end up setting many breakpoints. Instead of removing each breakpoint individually, you can remove all the breakpoints from a selected document by selecting the Edit > Remove All Breakpoints in File option or right-clicking Code view and selecting Remove All Breakpoints in File.

Starting a Debug Session

Once you have set your desired breakpoints, it's time to start debugging the application. The easiest way to start a debug session is to choose Debug view from the toolbar. By selecting this view, Flex Builder uploads the test file with any dependent files and starts a debug session with the Flash Player. Once the Flash Player debug session starts, the player contacts Flex Builder and starts to play your application. You can quickly access the Debug view by pressing Alt + F6.

The Debug view

Figure 3. The Debug view

If you prefer testing your applications in an external browser, you can still take advantage of Flex Builder’s debugging tools. To start an external debug session, select Debug in Browser from the toolbar, use the keyboard shortcut Alt+F12, or File > Debug. You can also start a debug session from the Run Debug button in Network Monitor and Output panels.

Starting a debug session in an external browser

Figure 4. Starting a debug session in an external browser

Using an external browser session for debugging is similar to using the Debug view. Flex Builder uploads the files and creates a debug connection with the external browser. When it encounters a breakpoint in an external browser session, Flex Builder regains focus and displays the code, just like in the Debug view.

The Debug Interface

Once a debug session starts, take advantage of four different panels, the Debug toolbar and the Debug menu. In the next section, I cover these different user interface elements and how they help you successfully debug your application.

Debug Toolbar and Menu

The first time you start a debug session, Flex Builder shows the debug user interface between the main Flex Builder toolbar and the Embedded Browser toolbar. You can move the Debug toolbar to a different location by dragging the panel grip to the left; you can detach it so that it floats freely; or you can hide the toolbar if you prefer to not use it. To hide the toolbar, right-click the main toolbar and deselect the debugging option. You can also show/hide the toolbar from the Debug menu.

The Debug toolbar

Figure 5. The Debug toolbar

From the Debug toolbar you can continue debugging your application, stop the current debug instance, restart the debug instance, step into a line of code, step over a line of code, step out of the current method, and access any of the files used in your application. You may also access the same functionality from the Debug menu if you would rather not show the toolbar.

Use the Continue button to continue playing your application

Figure 6. Use the Continue button to continue playing your application

With the Continue button, you continue playing your application. When Flex Builder encounters a breakpoint in your application, the debugger pauses on the current line of code that is about to execute and then opens the Code view to display the location of the current line. If you do not want to step through the lines of code, you can use the Continue button to move on in the application. When you press Continue, Flex Builder toggles back to the Debug view and plays the app until it encounters another breakpoint or until it is done executing the current functionality.

Use the Stop button when you are done with debugging the application

Figure 7. Use the Stop button when you are done debugging the application

When you have completed debugging your application and you want to make changes, use the Stop button. This button stops the current debug instance, closes the player connection, and returns you to the last view before you started debugging. It also closes any temp files created during debugging.

Use the restart button to reinitialize your application from the beginning

Figure 8. Use the restart button to reinitialize your application from the beginning

Sometimes during debugging, you need to reinitialize your application from the very beginning. Restart recompiles the file and starts a new connection to the Flash debug player. It is similar to using Refresh in the browser, but this button makes sure the debug instance and the controls refresh properly.

Use the Step In button to access any methods in the current line of code.

Figure 9. Use the Step In button to access any methods in the current line of code.

Use the Step In button to access any methods that are used in the current line of code. For example, if you have an ActionScript class that doesn't instantiate correctly with the following line of code:

var myCustomClass:CustomClass = new CustomClass();

In this case, you can set a breakpoint for the line of code and then use the Step In button. Flex Builder tries to find this class locally on your machine and open the file. If Flex Builder can't find the file locally (for example, the class is in user_classes or if the class was loaded through ActionScript), Flex Builder opens a temp file with the code.

In this example, Flex Builder opens a temp file and the debugger pauses the application on the first line of the constructor method of the CustomClass() class. As the name implies, this button steps into the method that the line calls. If you use Step In for a line like the following:

var myNum:Number = 12;

Step In would behave the same as Step Over because there is not a method to step into.

Use the Step Over button to skip over lines you don't need to step into.

Figure 10. Use the Step Over button to skip over lines you don't need to step into.

In most cases you don’t need to step into every line of code. Often, you just want to see the results of running a specific line of code. This is when you can use Step Over. Step Over runs the selected line and then pauses on the next line of code.

Use the Step Out button to return to the method that you stepped into

Figure 11. Use the Step Out button to return to the method that you stepped into

Step Out is useful when you step into a method and don’t want to step over every line of code in the stepped in method. Step Out returns you to the line of code that called the current method that the application paused upon. If you reach the top most method, Step Out behaves similarly to Continue.

In some situations Step Out may behave differently then you may expect. For example, let’s say that pressing a button calls a simple function. If you set the breakpoint in this function, start debugging, and press the button, your application will pause at that breakpoint. If you press Step Out, you would expect to have the application continue, but instead, the debugger opens a temp file and pauses in some large methods.

This seemingly unexpected behavior occurs because your defined function was not directly called by the button. The button triggers an event handler that calls your function. When you step out of your defined function, you step into the parent function that called it, in this case the event handler.

The Files button lists all the files that your Flex app uses

Figure 12. The Files button lists all the files that your Flex app uses

This item lists all the files that your Flex application currently uses. The first time you open this menu, you may be surprised by the number of files listed. You will also notice that most of the files listed are not files that you have written. What you see are all of the files that your application uses. Any time you use a control or container (such as an HBox class), the HBox class and all its parent classes load into the application. This is also true for the Focus manager, the History manager, and any other classes that are required for the SWF file at compile time. The nice thing about the Files list is that you can use it to set breakpoints in the precompiled Flex code so that you can trace how it interacts with your application.

The Files menu is probably one of the most important features of the Flex Builder debugger but at the same time it is often the most misunderstood feature. To get a better understanding of how the Files list can help you, it's important that you understand how Flex Builder manages breakpoints.

When you set a breakpoint in Flex Builder, it adds the file path to a list that it uses to match the code path in the SWD (a debug version of a SWF file that contains source code and other debugging functionality) to local files on your machine. When you debug an application, Flex Builder uses this list to specify where Flex Builder should request Flash Player to pause, at a specified breakpoint.

In some situations, Flex Builder cannot match the file path for the breakpoint to a file path in the SWD. A good example of this situation is when a file is in the user_classes folder. For example, say you have a color picker component located in the user_classes folder called MyColorChooser.as. You can link to this file in your application using:

<comp:MyColorChooser xmlns:comp="*" />.

When you start debugging in Flex Builder, this file is not next to the application MXML file (main.mxml) as the namespace defines, so Flex Builder is unable to associate a breakpoint. Note that the above syntax is completely legal and is a recommended way to reuse components. This is where the Files list becomes very useful.

Once the debug session starts, you can use the Files list to access the MyColorChooser code from the SWD file and set a breakpoint in Flex Builder.

Use the Files list to access other code from the SWD

Figure 13. Use the Files list to access other code from the SWD

Once you set this breakpoint, it will remain set over multiple debug sessions until you remove it.

You can remove these “internal breakpoints” by selecting Debug > Remove Internal Breakpoints or right-clicking in Code view and selecting the same option from the context menu. This option removes any breakpoints that you have set using the Files list. Also, if Flex Builder determines that the source file changed, a dialog box appears when you start the next debug session and asks if you wish to clear the breakpoints.

The Files menu is also useful when you need to debug MXML/ActionScript files that are called by the mx.managers.PopUpManager.createPopUp() or by explicit references to classes in ActionScript instead of using the implicit import reference. For example, Flex Builder does not see the explicit class’ breakpoints:

// Flex Builder does not see breakpoints set in
MyClass var myClassInstance = new com.macromedia.myapp.MyClass();

Flex Builder sees the class’ breakpoints here, however:

// Flex Builder sees breakpoints in MyOtherClass 
import com.macromedia.myapp.MyOtherClass;

var myOtherClassInstance = new MyOtherClass();

Variables Panel

Of the four debugging panels, you will probably use the Variables panel the most. You use this panel to inspect any defined variable in your application at the current breakpoint. The Variables panel is only available during a debug session and while paused at a breakpoint.

The Variables panel

Figure 14. The Variables panel

This vs. Local

The first time you stop at a breakpoint two expandable items in the Variables panel appear: "This" and "Local"” (Note: I will use quotes around these terms so that you know when I am referring to "This" as a variable and not simply the word). "This" contains all the non-local variables that are currently displayed in the current scope, while "Local" displays all the local variables defined in the current method/function.

I use the term non-local in place of global because "This" listed variables are not truly global, nor does it show all the global variables all the time. "This" displays the non-locals in the current scope of the breakpoint.

I hope this (no pun intended) example can help make this a little less esoteric. In the following example, you have your Application MXML file (main.mxml) and inside the app you’re using a MXML component called PieChart (PieChart.mxml) that is a custom component that you created.

In main.mxml, a variable called currentUsers stores the current number of users logged into your application; while in the PieChart.mxml, a variable called chartData stores the data used to display in the chart.

In main.mxml, for example, you have a method called addUser() and you decide to set a breakpoint inside this method. When your application calls this method and encounters the breakpoint, "This," the debugger will display currentUsers at the base of the "This" tree, but will not display chartData here. ChartData does not appear at the root of the tree because it is inside the PieChart scope and is a child property of PieChart.

If you set a break point inside a method of PieChart, the debugger will display chartData under "This" but will not display currentUsers because it is outside of the current scope or in this case, PieChart. As I said earlier, "This" shows the non-local (or in a way, global) variables of the current scope.

Showing the variables for various scopes

Figure 15. Showing the variables for various scopes

More simply, "This" displays the content that the ActionScript keyword "this" refers too. As you can tell, scoping can be a tricky and often complex issue. If you want to learn more about how Flex scoping works I highly recommend reading about it in the Flex documentation.

Changing Values

Another feature of the Variables panel is the ability to change the value of a displayed variable. This can be useful for testing error-checking code that requires a specific value that is hard to recreate, or when you want to skip ahead in a "for" or "while" loop.

To change a value in the Variables panel, double-click the values in the values column in the Variables panel.

Changing values

Figure 16. Changing values

You may notice that you can view and change the value of variables that you have defined as private in your code. Currently, the ActionScript 2.0 private keyword is only enabled at compile time. Once an application runs, you can change a private variable the same way as a public variable. This is not a recommended practice, but it is possible from the Variables panel.

When you change a variable value, you can only set the value to numbers and strings. You can not create or delete new items, change the type to another Flash Object (such as an Array, Date, and so forth), or add/remove object properties.

Complex Objects

One of the challenges of using the Variables panel is introspecting complex objects. The Variables panel reflects the true structure of Flash Objects by showing the constructor, the prototype, methods, and properties. This is especially true of XML Objects. The Flash XML Object does not reflect the actual XML structure, so determining node names and values is next to impossible when you look at the object.

To help you debug these complex objects, the Flex Builder development team built the XMLObjectOutput class, located in the Extras folder that Flex installs. This Class allows you to convert an XML Object to a named Object so that is easier to access properties and also allows you to trace out an object’s structure to the output window. You can also use this class to help parse XML data quickly and easily in your application. For more information about using XMLObjectOutput, see the ASDoc HTML file included in the Extras folder.

Watch Panel

In many debugging situations, you want to focus on just a few variables and their values as you walk through your application code. Sometimes these variables are buried deep in an object structure or the variable may be a local variable with a name that has been reused in multiple methods. If this is the case, use the Watch panel.

The Watch panel

Figure 17. The Watch panel

You can add variables to the Watch panel by simply double-clicking the left column of the Watch panel. This displays an edit field that you can use to add a variable name. You can also add a variable to the Watch panel from the Variables panel. If you see a variable that you want to add in the Variables panel, simply right-click the variable and choose “Add to Watch Panel.” The command copies the entire variable path and pastes it in the Watch panel for you.

To remove a variable from the Watch panel, double-click the variable name and then delete the text or right-click the variable and choose “clear selected item” from the context menu. If you want to remove all the variables from the Watch panel, select “Clear All” from the right-click context menu.

Flex Builder does not remove variables that you have added to the Watch panel between debug sessions or even Flex Builder sessions. This allows you to keep your preferred Watch variables as long as you need them without having to reset them every time you debug.

The Watch panel also allows you to change the value of a variable, just like the Variables panel.

Call Stack Panel

Before delving too deep into the Call Stack panel, it is important to have a firm grasp on scoping and event management in Flex. The Call Stack panel displays the current method/event where the application has paused and displays all the previous methods and events that Flex called to get to this point. Refer to the main.mxml and PieChart.mxml example:

In main.mxml you have added a button that draws the chart when a user clicks it. The Button has a click event that calls a prepChart() method located in main.mxml and then prepChart() calls drawChart() in the PieChart.mxml file. If you set a breakpoint in the drawChart() method, the Call Stack looks like the following:

The Call Stack for main.mxml

Figure 18. The Call Stack for main.mxml

The top of the Call Stack is the last method called and the bottom of the list is the first. The green arrow represents the current method/event that has the debugger focus, I will get deeper into this in a moment. Also notice that the first method called is actually not the prepChart() method, but a function called func(event). This method is the click handler of the button; Flex called it to process the prepChart() method.

Navigate the Call Stack by double-clicking the method; the green marker indicates that this method is now the selected event. This functionality is extremely important because it allows you to change the current scope/focus of the debugger and to track changes as Flex calls the methods.

In the example let's say that you create a new local variable in the prepChar() function called var initObj:Object. You use initObj to add properties and values and then you pass this variable to drawChart() in the PieChart component. In PieChart, the method drawChart() has an argument that is also named initObj; drawChart(initObj:Object).

Because these are both local variables and the variables are in different scopes (main scope and PieChart scope) this is legal code. Now that you have two variables with the same name, the way they appear in the Watch and Variable panels depends on your current location in the Call Stack.

If you select prepChart() as the current Call Stack focus and look at the Variables panel, initObj is the object that was created in the prepChart() method. If you switch the Call Stack focus to drawChart(), the initObj is now the argument variable that was passed to the method. In this situation, they are the same value, so this example might not seem that helpful. Consider the following situation.

Say that main.mxml has a variable called foo that stores the number 5. PieChart also has a variable called foo, and this variable stores a string, myString. In this example, PieChart has an id set to myChart.

If you set a breakpoint in prepChart() and then add foo and myChart.foo to the Watch panel, when the debugger encounters the breakpoint, the value for foo is the number 5 and myChart.foo shows myString. If you set the breakpoint in drawChart(), the method inside the PieChart component, foo displays myString and myChart.foo is undefined.

This occurs because the current scope is inside the PieChart component, the variable foo is the variable inside the PieChart scope, and myChart does not exist in this scope. If you use the Call Stack to return to the drawChart() method, the scope is now inside the main.mxml scope—and now foo is 5 and myChart.foo is myString.

Knowing the current scope is very important inside the Flex Builder debugger and the Call Stack panel allows you to navigate through the current scope and also access different scopes through the Watch panel.

Output Panel

Flex Builder uses the Output panel to display trace statements outputted from ActionScript. Trace statements only appear when you are in debug mode and do not output when simply running a Flex application. The reason you must be in debug for trace statements to output is that Flash Player ignores all trace statements unless you set debug to true for the player instance.

Trace statements in the Output panel

Figure 19. Trace statements in the Output panel

The No Breakpoints Dialog Box

When a Flex Builder debug session starts and Flex Builder can not find any breakpoints (local or internal), Flex Builder displays a dialog box asking if you would like to continue or set breakpoints. If you just want to run a debug instance to output traces, or if you plan to set breakpoints later, press Continue. Continue will start the initiation process of the app and execute it.

The dialog box will ask you if you would like to continue if you haven't set breakpoints

Figure 20. The dialog box will ask you if you would like to continue if you haven't set breakpoints

The key aspect of this dialog box is that it allows you to set breakpoints before application initialization. This can be very important when trying to track down a bug. Let’s say that you want to dynamically or explicitly load a class on the application initialization and you want set breakpoints in this class.

As mentioned earlier, the only way to set breakpoints in these classes is by using the Files menu, which is only available at debug time. Because this dialog box appears before the initialization, you can now access the Files List and set breakpoints in the classes you want before they have a chance to execute. Without this dialog box, you would not be able to access these classes before initialization and it could become a really frustrating debug experience.

Hopefully, you now have a much better understanding of how debugging in Flex Builder works. With the ability to inspect variables, set breakpoints in any file including Flex classes, output trace statements, and navigate through the different application scopes, debugging your application will be much faster and efficient.

About the author

James Polanco has been working with Macromedia for over four and a half years and is currently a QA Engineer on the Flex Builder development team. James has worked with and also provided support for Macromedia Flex Builder, Flex, JRun, Flash, Breeze, Director, Flash Remoting, ColdFusion, Dreamweaver, Flash Communication Server, and Authorware. Prior to working with Macromedia, James was an award-winning developer of computer-based training applications and educational websites for over three years.