Chapter 13. How Do I Work with the Display List?

13.0 Introduction

The new display architecture is one of the two biggest ActionScript changes in version 3.0. (The other biggest change comes in the form of the new event model, which the next chapter covers.) In this chapter, you’ll learn the basics of displaying content, which have been simplified over prior versions of ActionScript in a few ways.

To begin with, presenting visual assets to the user has become much more consistent. Previous ActionScript versions gave you a handful of different ways to display a movie clip, for example, and many more when factoring in the display of all types of visible assets. In ActionScript 3.0, however, all visual assets are displayed in the same general manner: create the asset (if necessary) using the new keyword, and then add it to the display list.

The display list is a type of linear array (although with its own access methods) of objects that the user can see. In simple terms, an empty SWF file has an empty display list, a SWF file with a single movie clip has a display list that contains one item, and so on. (More accurately, each SWF file includes the stage and main timeline at the root of the display list, but you can’t remove these, and so they’re not included as list indices.)

Although the display list can contain only objects with visual data, you can create such a display object without adding it to the display list. That is, a sound can’t be a display object because you can’t see it, but you can create a movie clip (which can be visible) without adding it to the display list.

You can hide a display object while it’s in the display list (by manipulating its visible or alpha properties, or even moving it offstage or covering it up with another display object). You can also remove an item from the display list without removing it from memory, thereby making it invisible to the user. Remember, however, that if an object has a visual component, it’s a display object and therefore can be included in the display list and, conversely, objects that are incapable of being seen by the user can’t be display objects and therefore can’t be included in the display list.

13.1 Choosing Which Type of Display Object to Use

Problem

You want to identify which kind of display object is best suited for a particular task.

Solution

Review the display object classes to determine which has the most useful set of properties, methods and/or events to satisfy your needs.

Discussion

Understanding the display list begins with looking at the classes that make up the collection of all objects that can be part of the display list, as seen in Figure 13-1. They originate with the DisplayObject class, which defines the basic properties, methods, and events all display objects share.

This chapter focuses on the most common display objects, but an overview of all the display list classes helps clarify their purposes. Begin on the left of Figure 13-1, with three eponymous classes.

Hierarchy of display list classes
Figure 13-1. Hierarchy of display list classes

Shape is a lightweight class that requires very little memory and performance overhead because it has no timeline or mechanism for reacting to mouse events. The result of creating and drawing into a shape with ActionScript is the same as the element created when you draw a shape by hand in the Flash authoring environment. Accomplishing this with code is a new feature in ActionScript 3.0.

Bitmap and Video classes are used, as you might expect, to display bitmaps and videos spawned from ActionScript. Skipping for a moment to the right half of Figure 13-1, you find three classes that you’re less likely to use directly. AVM1Movie references loaded SWF files created using ActionScript 1.0 or 2.0, MorphShape refers to timeline-based shape tweens, and StaticText refers to non-interactive text elements created in the Flash IDE. You can’t create instances of these classes, but they’re used as parent classes for other display objects.

Moving back to the center of the figure, InteractiveObject can’t be instantiated directly, but is a parent class for all interactive elements in the display list. The third row of the figure contains SimpleButton, TextField (so, in ActionScript 3.0, you can create true buttons on the fly), and another parent class that can’t be instantiated, DisplayObjectContainer. This latter class adds the ability for a display object to have children. While a bitmap couldn’t contain a nested movie clip, for example, any child of the DisplayObjectContainer class can.

The Stage class can’t be instantiated but does give you access to stage properties from any display object in the display list. Loader is used to load external display assets such as images and other SWF files, and Sprite is simply a movie clip without a timeline, provided for memory and performance optimization. Finally, MovieClip adds a timeline to Sprite, and the collection of display list classes is complete.

Choosing an appropriate display object depends largely on the task at hand. Some choices are clear, such as when dynamic bitmaps, videos, buttons, or text fields must be created, using their respective classes, or when external assets must be loaded into a Loader instance.

Others aren’t as obvious, but will soon become second nature. Shape instances serve primarily as canvases for dynamically drawing assets using the Graphics class, as discussed in Chapter 12. Because shapes have no timeline or user event capabilities, they’re best suited for drawing backgrounds and other objects that aren’t interactive. Movie clips are useful for frame-based animations, just as in the Flash IDE, and sprites are optimal for ActionScript-based animations when you don’t need a timeline, but you do need user events.

See Also

Chapter 12

13.2 Creating a New Display Object

Problem

You want to create an asset, such as a movie clip or sprite, which is derived from one of the DisplayObject classes.

Solution

Use the new keyword to create instances from scratch or from a Library linkage class.

Discussion

Creating any new display object is consistent throughout ActionScript 3.0, using the new keyword to spawn a new instance of the display object’s class. Typically, you want to store that instance in a variable that’s also typed to the display object’s class, or a relevant parent class. The following examples show the creation of four different display objects, and their corresponding variable references with data typing.

var mc:MovieClip = new MovieClip();
var sp:Sprite = new Sprite();
var tf:TextField = new TextField();
var sh:Shape = new Shape();

Building on that consistency, you can also create an instance of a Library-based display object using the same syntax. The only difference is that instead of using one of Flash’s built-in classes, you should use the name of the Library element’s linkage class.

Note

For more information about using the Library and linkage classes, see Chapter 7.

In this next example, a Library movie clip has been given a linkage class of Ball. The syntax still uses the new keyword to create an instance of the class, and stores the instance in a variable typed with the same class.

var ballObj:Ball = new Ball();

If desired, you can also type the variable with a relevant parent display class. For example, the Library element may have originated as a movie clip and, when given the linkage class of Ball, extended MovieClip as its base class. You could type the new instance of the Ball class as MovieClip, Sprite, or DisplayObject. You could use any one of the following three possible lines. This example relates to casting display objects to different data types, which will be covered later in the chapter.

var ballObj:MovieClip = new Ball();
var ballObj:Sprite = new Ball();
var ballObj:DisplayObject = new Ball();

While you can work with display objects immediately after creating them, you can’t see them until they’re added to the display list. This topic is covered in the next recipe.

See Also

13.3 Adding a Display Object to the Display List for adding a display object to the display list.

13.3 Adding a Display Object to the Display List

Problem

You want a display object to be visible to the user.

Solution

Use the addChild() method of the display object container’s class to add the object to the display list.

Discussion

A display object must be in the display list if it’s ever to be visible at runtime or be responsible for providing access to other display properties (such as a stage reference). This quality is independent of the visible or alpha property values of a display object, or other techniques for showing or hiding a visual asset.

The following script creates a new sprite and positions it at point (30, 30).

var sp:Sprite = new Sprite();
sp.x = sp.y = 30;

However, even though the sprite has x and y coordinates that are within the stage, you can’t see it until it’s added to the display list. The following method adds the specified display object to the top of the display list, regardless of the number of items already in the list.

addChild(sp);

The display list isn’t just a linear array of display objects; it’s also contiguous. That is, it can’t have gaps between display objects. This is a device for automating and optimizing depth management, and eliminates the need for the getNextHighestDepth() method in prior versions of ActionScript. Rather than specifying an arbitrarily high depth number to be sure a new visual asset is on top of another, using addChild() automatically appends the display object to the end (top) of the display list.

Further, the list automatically adjusts itself to eliminate any gaps. If you remove an object from the display list (discussed later in this chapter), then all objects higher in the list automatically drop down. If you insert an object in a position lower than other objects in the list (also discussed later in this chapter), then the higher objects all bump up a position.

So far, the sprite has no content, but you can add visual data through the use of another display object. The following script segment creates a shape and draws into it a 40-pixel by 40-pixel yellow square.

var sh:Shape = new Shape();
var g:Graphics = sh.graphics;
g.lineStyle(1, 0x000000);
g.beginFill(0xFFFF00, 1);
g.drawRect(0, 0, 40, 40);
g.endFill();

Previously, the sprite was added to the main timeline but, in this case, the shape will be added to the sprite. Display objects can be added to other display objects, and the former become children of the latter.

sp.addChild(sh);

You can certainly draw directly into a sprite. However, in addition to demonstrating hierarchical, or nested, display objects, this emphasizes that not all display objects behave the same way. On its own, the shape couldn’t function as an interactive element because it can’t process mouse clicks, among other events. However, by adding the shape to a sprite, the shape can then, by extension, be clickable.

See Also

13.1 Choosing Which Type of Display Object to Use for choosing a display object type, 13.4 Specifying the Depth of a Display Object for setting the depth of an object, 13.6 Removing a Display Object from the Display List, for removing an object from a display list, and 13.9 Casting a Display Object from One Type to Another for recasting a display object type.

13.4 Specifying the Depth of a Display Object

Problem

You want to place a display object at a particular visual stacking depth, or swap the visual depths of two display objects.

Solution

Based on need, use the addChild(), addChildAt(), setChildIndex(), swapChildren(), or swapChildrenAt() methods of the display object container’s class.

Discussion

You’ll often find it helpful to alter the depths at which display objects reside. Consider, for example, an interactive jigsaw puzzle. To simulate a real-world puzzle experience, it helps to move the clicked piece to the top of the pile while dragging it to the puzzle board.

You have several ways to change the stacking order of display objects. The first is simply to add the same object to the display again. In the following code, a sprite (red, 0xFF0000) is added to the display list first, followed by a movie clip (blue, 0x0000FF). However, the first sprite is added to the display list again. Because it’s the same object, it’s automatically removed from its prior position and placed in its new position. As a result, the sprite moves to the top of the stacking order.

var sp:Sprite = new Sprite();
drawSquare(sp, 0xFF0000);
sp.x = sp.y = 20;
addChild(sp);

var mc:MovieClip = new MovieClip();
drawSquare(mc, 0x0000FF);
mc.x = mc.y = 40;
addChild(mc);

addChild(sp);

function drawSquare(obj:Object, col:uint):void {
    var g:Graphics = obj.graphics;
    g.beginFill(col, 1);
    g.drawRect(0, 0, 40, 40);
    g.endFill();
}

You also have more direct ways of placing a display object at a specific level. The addChildAt() method is a companion to addChild() but lets you dictate a destination depth for the display object. The method has two parameters: the object being placed, and the target depth. As with addChild(), the object on which this method is called dictates scope—the display list to which this child will be added. Omitting an object reference before the method adds the child to the current scope—the display list in which the omitted object resides.

For example, the following adds a library symbol, stored in the variable boxSp, to the bottom of the main timeline (the current scope) by specifying a depth of zero.

var boxSp:Sprite = new Box();
addChildAt(boxSp, 0);

For example, the following adds a display object to the main timeline (the current scope) because no target for addChild() is specified. In this case, it adds a library symbol, stored in the variable boxSp, to the bottom of the main timeline by specifying a depth of zero.

var boxSp:Sprite = new Box();
addChildAt(boxSp, 0);

If you wanted to add boxSp to the bottom of the child list of an existing display object container, such as the previously created movie clip mc, the syntax would follow the examples for addChild()and look like this:

mc.addChildAt(boxSp, 0);

See Also

13.3 Adding a Display Object to the Display List for adding a display object to the display list.

13.5 Finding a Display Object

Problem

You need to create a reference to a display object, but you have access to only its name or position in the display list.

Solution

Use the getChildAt() or getChildByName() methods of the display object container’s class.

Discussion

People often want to access a display object without already having a reference to the object in question. For example, you may want to generate an object’s name by combining strings or accepting user input, or you may want to loop through all children of a container addressing each item by child index.

The first line of the following ActionScript block retrieves a reference to an object by using its name. The second shows how to reference the bottom-most display object (because it gets the display list child at depth zero).

var dispObj:DisplayObject = getChildByName("claire");
var dispObj2:DisplayObject = getChildAt(0);

Both these methods are really useful. The latter makes it possible to work with an object at any depth, even without knowing which object currently occupies that position in the display list. You virtually require the former when creating display objects with ActionScript because of a small change in the new version of the language.

In ActionScript 2.0, you could use a name that was added to a symbol instance with code to reference its properties or methods. That is, if you created an empty movie clip, you could assign it a name with ActionScript, and then use that name as a proper instance name as if it were applied in Flash’s Property inspector.

In ActionScript 3.0, you can’t do this any more. The string used for the instance’s name property remains a string—a property value—and can’t be evaluated as an object. The following code example illustrates this point. The first code segment creates, names, and positions a display object, and then adds it to the display list. The second segment traces the x coordinate of the display object, using its programmatically assigned name as an instance reference. The result is an error because the value of the name property isn’t understood to be a proper object.

var sp:Sprite = new Sprite();
sp.name = "claire";
sp.x = 100;
addChild(sp);

trace(claire.x);
//yields error:
//1120: Access of undefined property claire.

The simple solution is to use the getChildByName() method to return a fully qualified object reference, as seen here:

var dispObj:DisplayObject = getChildByName("claire");
trace(dispObj.x);
//yields 100

See Also

13.4 Specifying the Depth of a Display Object, for setting the depth of the display object.

13.6 Removing a Display Object from the Display List

Problem

You want a display object to be hidden from view, unable to receive events, and/or disassociated from familial relationship with other display objects.

Solution

Use the removeChild() or removeChildAt() methods of the display object container’s class to remove the object from the display list.

Discussion

You have a few ways to hide a display object, and more than one way to block events from reaching a display object. These tasks required a little thinking in prior versions of ActionScript, but are incredibly easy when using the display list. You just have to remove the display object in question from the display list.

The following line removes a display object sp from the scope in which the display object resides. Continuing the scenario shared by other recipes in this chapter, consider the sprite, sp, in the main timeline.

removeChild(sp);

As with addChild(), you can also invoke this method in another scope. The following, for example, removes a hypothetical nested movie clip mc from its parent sp.

sp.removeChild(mc);

Finally, just as you could add a child to a specific depth with addChildAt(), you can also remove a child from a specific depth. The following example removes the first child, or child at the lowest depth, of all nested display objects within sp.

sp.removeChildAt(0);

Note that none of these methods removes a child from memory. They all remove only the object in question from the display list. So you can temporarily remove a child from the display list and restore it later. If you want to remove a display object from memory as well, you can set it to null.

The following repeats the earlier example of removing sprite sp from the display list, but then also nullifies the sprite so it can be marked for removal from memory by the garbage collector.

removeChild(sp);
sp = null;

See Also

13.3 Adding a Display Object to the Display List for adding a display object to the display list and 13.4 Specifying the Depth of a Display Object for setting the depth of a display object.

13.7 Working with Children of a Display Object Container

Problem

You want to determine if a display object has children or a particular child, or you want to disable the mouse events of all children.

Solution

Check to see if a display object is of type DisplayObjectContainer to see if it can have children. Use the numChildren property to determine if a display object container has children, or the contains() method to determine if a particular child of the container exists. Use the mouseChildren property to enable or disable mouse events for all children of a container.

Discussion

Every visible element is a display object but not all display objects are display object containers as shown in Figure 13-1. Neither shapes, bitmaps, nor videos, for example, are display object containers and, therefore, can’t have children.

When trying to work with children of an object, it helps to avoid errors by first making sure that the object can have children. You do this by checking to see if the instance in question qualifies as a DisplayObjectContainer data type, using the is operator. This conditional traces a result if mc is a movie clip, because a movie clip is a display object container:

var mc:MovieClip = new MovieClip();

if (mc is DisplayObjectContainer) {
    trace("container");
}

You can use this technique to make sure that any properties or methods of a container are used without error. For example, the following code replaces the string in the previous trace statement with a use of the numChildren property to see how many children are nested within the movie clip:

if (mc is DisplayObjectContainer) {
    trace(mc.numChildren);
}

If you want to see if a particular child exists, you can use the contains() method. The following example traces a result only if a child reference sp is found inside the container mc.

var mc:MovieClip = new MovieClip();
var sp:Sprite = new Sprite();
mc.addChild(sp);
addChild(mc);

if (mc is DisplayObjectContainer) {
    if (mc.contains(sp)) {
        trace("sp found");
    }
}

Finally, it’s handy to know how to prevent children of a display object from receiving mouse events. This will become more apparent when events are discussed in the next chapter, but consider this example. If you dynamically create a display object to serve as a button, and add to that object a text field child to serve as the button’s label, then the text field reacts to the cursor and possibly trap mouse events when not wanted.

For example, you may not see the hand cursor responsible for indicating the presence of an interactive element and, depending on how you set up your file, the text field may prevent the button from reacting to a mouse click.

While you certainly want a text field to be able to react to the mouse at other times, the button label in this example shouldn’t interfere with standard user interface design. In this case, it’s handy to use the mouseChildren property of the button object to disable mouse events for all children.

To demonstrate this change, you need a little code for handling text and events before covering that material in greater detail in later chapters. For now, the ActionScript has been broken into four segments. The last two blocks set up the text and mouse event, respectively.

The first block creates a new sprite, draws a yellow rectangle inside, and adds the sprite to the display list. The second block contains two properties that illustrate the usefulness of mouseChildren. The buttonMode property tells Flash Player to treat the sprite as if it were a button, and display the desired hand cursor when rolling over the button. The commented line uses the mouseChildren property, and will be explained following the script.

var sp:Sprite = new Sprite();
var g:Graphics = sp.graphics;
g.beginFill(0xFFFF00, 1);
g.drawRect(0, 0, 100, 30);
g.endFill();
addChild(sp);

sp.buttonMode = true;
//sp.mouseChildren = false;

addLabel(sp);
function addLabel(obj:Sprite):void {
    var txtFrmt:TextFormat = new TextFormat();
    txtFrmt.size = 24;
    txtFrmt.align = TextFormatAlign.CENTER;

    var txtFld:TextField = new TextField();
    txtFld.width = 100;
    txtFld.height = 30;
    txtFld.text = "Label";
    txtFld.setTextFormat(txtFrmt);

    obj.addChild(txtFld);
}

sp.addEventListener(MouseEvent.CLICK, onClick);
function onClick(evt:MouseEvent):void {
    trace("button clicked");
}

By default, mouseChildren is true, letting children of an object receive events. In this state, you’ll notice that the cursor doesn’t change from pointer to hand when rolling over the button. This is because the text field is the same size of the button, and is intercepting the cursor before it reaches the button. By un-commenting the mouseChildren line, thereby setting the property to false, no children of the sprite receive mouse events, and the button behaves normally.

13.8 Working with Parents of a Display Object

Problem

You want to refer to a parent or ancestor of a display object.

Solution

Use the parent property of the display object.

Discussion

You’ll often need to reference a parent or ancestor—a parent’s parent, or (informally) grandparent—of a display object. Accessing the parent of a display object is similar to working your way through a directory structure on your computer. Any parent of a display object also qualifies as a display object container by the mere fact that it has children. Moving up one level, so to speak, from child to container requires only the use of the parent property.

The following example revisits the red and blue squares from earlier recipes. The parent, or blue movie clip, is positioned at point (20, 20) in the main timeline. The child, or red sprite, is offset another 30 pixels in both the x and y directions. Since a display object’s location is relative to its parent, querying the x location of the child returns a value of 30, but the x location of its parent is 20.

To check these results, the third block of this script traces the x coordinate of the sprite and its parent.

var mc:MovieClip = new MovieClip();
drawSquare(mc, 0x0000FF);
mc.x = mc.y = 20;
addChild(mc);

var sp:Sprite = new Sprite();
drawSquare(sp, 0xFF0000);
sp.x = sp.y = 30;
mc.addChild(sp);

trace(sp.x);
trace(sp.parent.x);

function drawSquare(obj:Object, col:uint):void {
    var g:Graphics = obj.graphics;
    g.beginFill(col, 1);
    g.drawRect(0, 0, 40, 40);
    g.endFill();
}

Note

This works without further qualification because the x property is available to both display objects and display object containers. When you attempt to use a property or method that isn’t universally available, the ActionScript 3.0 compiler may object and require additional information to handle the request. You can see this in the next recipe.

See Also

13.9 Casting a Display Object from One Type to Another for casting a display object from one type to another.

13.9 Casting a Display Object from One Type to Another

Problem

You want to explicitly convert a display object from one type to another. Alternately, you receive a compiler error telling you that a property or method you’re trying to manipulate may be undefined due to a static reference to DisplayObject or DisplayObjectContainer.

Solution

Cast the display object to the appropriate type, officially declaring its type for the compiler.

Discussion

Casting is the process of explicitly changing an object from one data type to another. For example, you can change a string to an integer by casting it with int(). The following casts two strings, and traces the outcome of adding the resulting integers.

trace(int("1") + int("2"));
// 3

If the strings had not been cast to integers prior to using the plus (+) operator, the result would have been an execution that concatenated the strings “1” and “2” to get “12” rather than adding the two numbers 1 and 2 to get 3. You can also cast from one related display object type to another, and the following scenario is a good example of when this is required.

In the previous recipe, the parent property was used to query the x location of a parent container. This was possible because both the parent and child had an x property. However, quite often the ActionScript compiler is unsure whether or not a targeted parent has the requested property or method in its class.

For instance, a movie clip could be a child of a sprite, or a sprite could be a child of a movie clip. If you were to query a property that applied only to a movie clip, using nothing more than a passing reference to a display object’s parent, the compiler wouldn’t know the data type of the parent and, therefore, couldn’t know if the property existed. Here’s some example code:

var mc:MovieClip = new MovieClip();
drawSquare(mc, 0x0000FF);
mc.x = mc.y = 20;
addChild(mc);

var sp:Sprite = new Sprite();
drawSquare(sp, 0xFF0000);
sp.x = sp.y = 20;
mc.addChild(sp);

var totFr:int = sp.parent.totalFrames;
trace(totFr);

function drawSquare(obj:Object, col:uint):void {
    var g:Graphics = obj.graphics;
    g.beginFill(col, 1);
    g.drawRect(0, 0, 40, 40);
    g.endFill();
}

In this situation, you get an error that says something like this:

//1119: Access of possibly undefined property
totalFrames through a reference with static type flash.display:DisplayObjectContainer.

Briefly, totalFrames is a property of a movie clip but is missing from other types of display object containers (such as sprite). Without telling the compiler the parent is a movie clip, it throws an error.

The solution is to cast the parent as type MovieClip, just as the previous example cast from string to integer using int().

var totFr:int = MovieClip(sp.parent).totalFrames;
trace(totFr);

Once the compiler explicitly knows this, it doesn’t generate an error, and the script functions as intended.

See Also

13.8 Working with Parents of a Display Object for working with the parents of display objects.

13.10 Changing the Parent of a Display Object

Problem

You want to move a child display object from one parent to another.

Solution

Use the addChild() method (or equivalent) and ActionScript 3.0’s automatic display list management to re-parent the child on the fly.

Discussion

One of the display list’s greatest qualities is the ability to change a display object’s parent with very little effort. In the following setup, the sprite sp is a child of the movie clip mc. As a result, the sprite displays at point (50, 50), which is the location of mc.

var mc:MovieClip = new MovieClip();
mc.x = mc.y = 50;
addChild(mc);

var sp:Sprite = new Sprite();
var g:Graphics = sp.graphics;
g.beginFill(0xFF00FF, 1);
g.drawRect(0, 0, 40, 40);
g.endFill();
mc.addChild(sp);

var mc2:MovieClip = new MovieClip();
mc2.x = mc2.y = 150;
addChild(mc2);

//mc2.addChild(sp);

However, if you uncomment the last line of the script, sp is again added to the display list, but this time, as a child of mc2. Because the same display object reference is being added to the display list twice, the first occurrence is automatically removed from the list, and the object moves to become a child of mc2. Consequently, the sprite now displays at point (150, 150), the location of mc2.

Re-parenting on the fly has many benefits. Consider, for example, a drag-and-drop scenario where every time you drop an item onto a new parent, the item becomes a child of the drop target. You could easily use this setup to group objects, manipulate their properties as a single item, and even remove an entire group of objects from the display list, simply by altering one parent.

13.11 Referencing the Stage Through a Display Object

Problem

You want to work with properties, methods, or events related to the stage, using a display object as a point of reference.

Solution

Use the stage property of any relevant display object already in the display list.

Discussion

ActionScript 3.0 no longer has a ubiquitous reference to the stage. Instead, you typically access the stage through the stage property of a display object. For this to be possible, however, the display object must be a child of a display list.

The following attempt to query the stage frame rate generates an error because the stage property of the display object is null. You can see this directly by trying to trace the stage property itself, in the last line of this script block.

var sp:Sprite = new Sprite();
trace(sp.stage);
//null

trace(sp.stage.frameRate);
//TypeError: Error #1009: Cannot access a property
or method of a null object reference at main_fla::MainTimeline/frame1()

Once the display object is added to the display list, however, the stage property is valid, and no error occurs. The stage property also then correctly traces a reference to the Stage instance.

addChild(sp);
trace(sp.stage);
//[object Stage]

trace(sp.stage.frameRate);
//12

You most often encounter this issue when using classes, simply because it’s easier to get a reference to the stage within a Flash timeline frame script. This is because the main timeline itself is automatically a part of the display list, and can reference the stage. However, this timeline-based example still illustrates the problem and, ideally, this will help you avoid null object reference errors when the stage is involved.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset