How do I prevent memory leaks in Flex when rerunning effects? - apache-flex

This application is a much simplified version of what I am trying to accomplish, some smoothing of some motion on the screen by using a composite animation and rerunning it as things change, and using bindings to set some of the values of the animation. The animation is periodically stopped, and then restarted. valueFrom is not set so a property value just continues from where it was towards a new goal. In this example, I'm animating a Rect's left/top towards mouse's X/Y to make it chase the mouse.
Problem is the memory of this application continues to grow if you wait a little while and continue to move the mouse. So what should I be doing that I am not?
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="creationCompleteHandler(event)"
mouseMove="mouseMoveHandler(event)"
mouseOut="mouseOutHandler(event)"
>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private static const RECT_HALF_SIZE:int = 5;
private static const NO_CHASE:int = -1000;
[Bindable]
private var lastMouseX:int = NO_CHASE;
[Bindable]
private var lastMouseY:int = NO_CHASE;
private var evalTimer:Timer = new Timer(100);
protected function creationCompleteHandler(event:FlexEvent):void
{
evalTimer.addEventListener(TimerEvent.TIMER, function(event:TimerEvent):void { evalChase(); });
evalTimer.start();
}
protected function mouseOutHandler(event:MouseEvent):void
{
lastMouseX = lastMouseY = NO_CHASE;
evalChase();
}
protected function mouseMoveHandler(event:MouseEvent):void
{
const reStart:Boolean = (lastMouseX == NO_CHASE);
lastMouseX = event.localX;
lastMouseY = event.localY;
if(reStart)
evalChase();
}
private function evalChase():void
{
doChase.stop();
doChase.end();
if(lastMouseX == NO_CHASE)
return;
doChase.play();
}
]]>
</fx:Script>
<fx:Declarations>
<s:Linear id="linearEaser" />
<s:Parallel
id="doChase"
duration="2000"
>
<s:Animate target="{chaser}" easer="{linearEaser}" >
<s:SimpleMotionPath property="left" valueTo="{lastMouseX-RECT_HALF_SIZE}" />
</s:Animate>
<s:Animate target="{chaser}" easer="{linearEaser}" >
<s:SimpleMotionPath property="top" valueTo="{lastMouseY-RECT_HALF_SIZE}" />
</s:Animate>
</s:Parallel>
</fx:Declarations>
<s:Rect
id="chaser"
top="0" left="0"
width="{2*RECT_HALF_SIZE}" height="{2*RECT_HALF_SIZE}"
>
<s:fill>
<s:SolidColor color="red" />
</s:fill>
</s:Rect>
</s:WindowedApplication>

Don't think you're actually doing anything wrong in this code, I copied into a new Flex 4.6 project and ran it, I could see what you're saying with regard to the ADL process itself increasing slightly in memory consumption over time, particularly after it stops motion then begins again, however I tried running this in Flash Builder with the profiler and it seems the swf itself isn't really leaking any memory, it stayed right around 1.1 MB for me (up to about 1.4, but then back down) it seems it had a fair amount of Vector.<*> objects in memory though I'm not clear on what is being stored in those objects.

Related

Flex spark list to render images

I am new in flex. Currently i am going to build a flex album, but I get a problem about
the render in image by spark list.
the problem is this last 2~3 thumbs can not be properly displayed, as you can see as follows:
http://www.j-rich.com/Problem
and it will look like:
http://www.j-rich.com/Problem/show.jpg
for the source code, you can right click and choose view source in the demo
Any suggestion will be appreciated, thank you very much.
Sincerely,
Yuan-Hsu Liao
Add cachePolicy="on" to your Image control in ItemRenderer. But I don't recomend to use this kind of huge images as thumbnails. Looks like Flash has some limitations in this field.
This is correct for me, my resolution is 1920*1080. I use FLEX SDK4.5.1, flashplayer 11.8.
By the way, you should better override the set data function in the ItemRenderer, and set img source in the function, like this:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
override public function set data(value:Object):void {
super.data = value;
var url:String = value as String;
img.source = url;
positionImg();
}
private function positionImg():void
{
this.ima.width = 136;
this.ima.height = 105;
this.ima.x = 0;
this.ima.y = 0;
}
]]>
</fx:Script>
<s:Group id="group" x="0" y="0" width="170" height="85">
<s:Image id="img" x="0" y="0" scaleMode="letterbox"/>
</s:Group>
</s:ItemRenderer>
ItemRenderer is recycled, so it's better to do some stuff in the set data()
Check whether ur Padding given is Correct...or else Adjust the same.

Displaying black and red ToolTips as speech baloons

I'm porting a card game from pure Flash/AS3 to Flex 4.5:
I'm almost done, but the "speech baloons" marked by the blue color in the screenshot above are missing.
Those "speech baloons" fade in, display red (if they contain hearts or diamonds char) or black text and finally fade out.
I'm trying to implement those as mx.controls.ToolTips and have prepared a simple test case, where 3 users are represented by smiley-buttons and you can push a "Talk"-button to make them talk:
<?xml version="1.0"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
width="400" height="300"
initialize="init();">
<fx:Declarations>
<s:Fade id="fadeIn" alphaFrom="0" alphaTo="1" duration="2000"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.managers.ToolTipManager;
private var i:uint = 0;
private function init():void {
ToolTipManager.enabled = false;
ToolTipManager.showEffect = fadeIn;
}
private function talk():void {
var str:String = 'Me plays 10' + (i % 2 ? '♥' : '♠');
// this does not make the ToolTip appear?
this['user' + (++i % 3)].toolTip = str;
// how to set color according to isRed(str)?
}
private function isRed(str:String):Boolean {
return (str.indexOf('♦') > 0 || str.indexOf('♥') > 0);
}
]]>
</fx:Script>
<s:Button id="user0" horizontalCenter="0" bottom="0" label=":-)" />
<s:Button id="user1" left="0" top="0" label=":-)" />
<s:Button id="user2" right="0" top="0" label=":-)" />
<s:Button right="0" bottom="0" label="Talk!" click="talk()" />
</s:Application>
Can anybody please give me hints?
How to make ToolTips appear at will? (and not just on mouse hover)
How to change their color (I only found how to set it once by CSS)
UPDATE:
I've tried the following
private var tip0:ToolTip;
private var tip1:ToolTip;
private var tip2:ToolTip;
private function talk():void {
var str:String = 'Me plays 10' + (++i % 2 ? '♥' : '♠');
var btn:Button = this['user' + (i % 3)];
var tip:ToolTip = this['tip' + (i % 3)];
tip = ToolTipManager.createToolTip(str, btn.x + 10, btn.y + 10, "errorTipBelow", IUIComponent(btn)) as ToolTip;
}
but this does not work too well - no effects, no disappearing (I guess I have to call destroyToolTip myself). I wonder if ToolTip can be (ab)used for my purpose of representing "speech baloons" in an elegant way at all...
Personally, I have found the tool tip system rather limiting, and any time I want to do something a bit more different, it just seems easier to implement it manually. Generally in this case I would add a PopUpAnchor control to the components that need these overlay displays. Then you have full manual control over what is shown, and exactly how it is shown.
http://blog.flexexamples.com/category/spark/popupanchor-spark/
There are quite a few ways to do this though as well as just building the tooltip component as a subclass of Group, adding it as a child, and keeping track of it.

Problem with displaying AS3 code in Flex

I have AS3 script bitfade.text.steel returning type Sprite. It works in Flash environment but not in FLEX. In Flex it displays nothing. No errors appear. It looks like the attached code also works. I use Flex SDK 4.5
Can you give me a clue what the problem with this code might be?
English is not my native language.
If there are any errors please correct me.
Chris
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="creationComplete();" >
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import bitfade.text.steel;
import flash.display.Sprite;
import mx.core.UIComponent;
function creationComplete(){
var textSteel = new steel("config.xml");
if(textSteel is Sprite){
trace("it is a sprite");
}
//var textSteelName:String = getQualifiedClassName(textSteel);
//trace(textSteelName);
textSteel.x = 150;
trace("this is visible on the screen");
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xFFCC00);
sprite.graphics.drawCircle( 40, 40, 40 );
sprite.graphics.endFill();
var wrapper:UIComponent = new UIComponent();
wrapper.addChild(sprite);
wrapper.addChild(textSteel);
animationStage.addElement(wrapper);
}
]]>
</fx:Script>
<s:Group id="animationStage" visible="true" x="50" y="50">
<s:Label text="test">
</s:Label>
</s:Group>
</s:WindowedApplication>
If I switch your custom class to a Sprite, and draw something on it, it shows up. Therefore I Believe there is a bug within your steel class. A sprite won't have any size until something is inside it with a size. There is no indication of the code you've shown what happens inside your steel class.
My sample:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="creationComplete();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
// import bitfade.text.steel;
import flash.display.Sprite;
import mx.core.UIComponent;
public function creationComplete():void{
var textSteel : Sprite = new Sprite();
if(textSteel is Sprite){
trace("it is a sprite");
}
//var textSteelName:String = getQualifiedClassName(textSteel);
//trace(textSteelName);
textSteel.x = 150;
// JH Code added new
textSteel.graphics.beginFill(0xFFCC00);
textSteel.graphics.drawRect(0,0,100,100);
textSteel.graphics.endFill();
trace("this is visible on the screen");
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xFFCC00);
sprite.graphics.drawCircle( 40, 40, 40 );
sprite.graphics.endFill();
var wrapper:UIComponent = new UIComponent();
wrapper.addChild(sprite);
wrapper.addChild(textSteel);
animationStage.addElement(wrapper);
}
]]>
</fx:Script>
<s:Group id="animationStage" visible="true" x="50" y="50">
<s:Label text="test">
</s:Label>
</s:Group>
</s:WindowedApplication>
I think you need to set the width and height of the wrapper UIComponent instance.
UIComponents don't automatically resize to their content so it's showing up with a width and height of 0.

Flex/AIR: To resize all components inside a WindowedApplication

It's interesting. If you set stage.scaleMode = StageScaleMode.EXACT_FIT; all components are resized when you resize the window, BUT there is a grey stripe at the bottom of the window that is not.
What does that mean?
By the way, is it possible to take that grey line/stripe off from the window?
Try to resize this window and you'll see what happens:
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:local="*"
applicationComplete="initApplication(event)" width="800" height="600" preloaderChromeColor="#FFFCFC">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private function initApplication( evt:FlexEvent):void{
stage.scaleMode = StageScaleMode.EXACT_FIT;
var timer:Timer = new Timer(3000);
timer.addEventListener( TimerEvent.TIMER, onTimer );
timer.start();
}
private function onTimer( evt:TimerEvent ):void{
this.width = 600;
trace(this.stage.stageWidth, this.stage.stageHeight);
}
]]>
</fx:Script>
<s:Button x="185" y="245" label="Button" width="112" height="61"/>
</s:WindowedApplication>
There is also a timer just for checking if the Stage's size is the same as the application window's one.
The gray stripe is the statusBar property of the WindowedApplication class. Turn it off by setting showStatusBar="false" inside the WindowedApplication tag.
That grey stripe at the bottom is the statusbar from the windows chrome, you need to set the 'systemChrome' tag to false in the app xml descriptor file to remove it or do showStatusBar="false".

Flex: Moving canvases between several ui elements

I need to animate a lable movement between 2 canvases...
The mxml example of the code is:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="main()" frameRate="1">
<mx:Script>
<![CDATA[
import mx.controls.Label;
public function main():void
{
onEnd();
}
private function onEnd():void
{
(canv1.getChildAt(0) as Label).move(canv2.x, canv2.y);
}
]]>
</mx:Script>
<mx:Panel x="208" y="0" width="190" height="200" layout="absolute" title="Panel2" id="d">
</mx:Panel>
<mx:Panel width="200" height="200" id="c" title="Panel 1">
<mx:Canvas width="135" height="56" id="canv1" label="c1" themeColor="#79B4DA" backgroundColor="#65D565">
<mx:Label text="Move me after event" y="10"/>
</mx:Canvas>
<mx:Canvas width="135" height="79" id="canv2" label="C2" backgroundColor="#E4CACA">
</mx:Canvas>
</mx:Panel>
</mx:Application>
Currently the problem is that the label actually do not leave borders of the first canvas (I see scrollbars instead of it).
I think this is related to globalToLocal conversion problems, but do not understand how to use it.
Also another question is how to animate the movement corretly, because move function performs movement without any visible action.
(The movement happens seamlessly).
I don't think the move function will solve this for you since it will only move the label within it's parent, just as Robusto has commented above.
The way to go about this would perhaps be to see to it that you first detach the label from its parent. Then move it, and add it as a child to the other canvas. Manipulating x,y coordinates will not implicitly change the parent for you. That will always have to be done explicitly, which is good...
So for example, to actually switch parent you would need to do something like this (pseudo code):
/**
* This function only switches the parent.
*/
private function moveLabel(label:Label) {
label.parent.removeChild(label);
canv2.addChild(label);
}
If you want this action to be animated you would first have to detach the label from the canvas and see to it that it is added to the parent of the canvas, in your case, the panel with id "c". Then you can tween it into position and add it to the correct canvas.
TweenLite is a great library for tweening. http://www.greensock.com/tweenlite/
But I guess the main lesson here is that manipulating coordinates will never result in a new parent for the component you are moving.
Update: Here's a complete example of how you could solve this, take into account that the code is not very nice looking, but it contains a simple example of animation.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="main()">
<mx:Script>
<![CDATA[
import mx.controls.Label;
import flash.geom.Point;
import gs.TweenLite;
import gs.easing.Expo;
public function main():void
{
onEnd();
}
private function onEnd():void
{
var label:Label = canv1.getChildAt(0) as Label;
var originX:int = label.localToGlobal(new Point(label.x, label.y)).x;
var originY:int = label.localToGlobal(new Point(label.x, label.y)).y;
label.parent.removeChild(label);
stage.addChild(label);
label.x = originX;
label.y = originY;
TweenLite.to(label, 1.5, {y: "80", ease:Expo.easeOut, onComplete:onFinishTween, onCompleteParams:[label]});
}
private function onFinishTween(label:Label):void {
stage.removeChild(label);
label.x = canv2.globalToLocal(new Point(label.x, label.y)).x;
label.y = canv2.globalToLocal(new Point(label.x, label.y)).y;
canv2.addChild(label);
}
]]>
</mx:Script>
<mx:Canvas width="135" height="56" id="canv1" label="c1" themeColor="#79B4DA" backgroundColor="#65D565" y="-1" x="9">
<mx:Label text="Move me after event" y="10"/>
</mx:Canvas>
<mx:Canvas width="135" height="79" id="canv2" label="C2" backgroundColor="#E4CACA" y="90" x="8">
</mx:Canvas>
</mx:Application>

Resources