本节内容:
1.弱引用的使用原则
2.listener的不同和this关键字的指向。
继续上次的话题。在讲listener 和 this关键字之前,我们先来讲讲一个高级话题:
弱引用的使用原则。
继续上次的话题。在讲listener 和 this关键字之前,我们先来讲讲一个高级话题:
弱引用的使用原则。
新手可以不看,因为暂时用不到。但这个话题很有必要。当设计大型RIA应用程序时,弱引用必须要了解。
弱引用从原则上来讲,其引入是为了防止无意识的对象保留(unintentional object retention)引起的内存泄漏。
什么是无意识的对象保留?一般情况下,对象的逻辑生命周期和实际生命周期应当相同。但是在某些情况下,比如事件侦听器机制,我们可能会创建一个引用,它在内存中生存的时间比我们预期的要长很多。比如说,下面的例子中,即使删掉了侦听器lis,但事件还是能被继续捕捉。这是由于并没有removeEventListenr,那么系统中还会保留着对侦听器的引用。
如果没有把addEventListener中对侦听器的持有改成弱引用,那么这个侦听器会一直存在、耗掉内存不被人发觉。但如果设成了弱引用,那么垃圾回收器过段时间后会将侦听器占用的内存回收,此时侦听器从物理意义上才真正的被销毁了。
在销毁之前,这个侦听器还会继续存在,继续作用。这就是为什么下例中虽然已经把useWeakReference设为了true,但是还是会有作用。
那么什么时侯垃圾回收器(Garbage Collector)才会来回收呢?
唔,这要看它高兴了,快的话10分钟,慢的话一个月。哈哈,开玩笑,垃圾回收器的工作时间咋一看确实是不可测的,但也有规律可循。但这个问题探讨在本系列教程中显得过于艰深,黑羽会单独撰文来说明垃圾回收器的部分工作机制。
那么推论来了,我们凭什么要把useWeakReference设为false呢?除非我们有意要让某个侦听器在失去了其他所有引用的时候还要工作,才有可能这样做。但谁会有这样疯狂的想法呢?道哥还是包世宏?
所以,我建议,大家不妨养成习惯,把useWeakReference设为true。
当然最好的做法是始终记得不用侦听器了,一定要removeEventListener。在这一点上,我们要坚持“始乱终弃”!!
//这个是Document Class,建个fla,绑定这个class。忘了,就看我第三篇教程。
package
{
import flash.display.MovieClip;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;public class LearnEvents extends MovieClip
{
function LearnEvents() {
var lis:Function = function () {
trace ("听到了鼠标Click事件!");
}
var kingda_s:KingdaSprite = new KingdaSprite(0xFFCC00, "kingdaSquare");
addChild(kingda_s);
kingda_s.addEventListener(MouseEvent.CLICK, lis, false, 0, true); //瞧,最后一个参数,已经把弱引用设为true了
lis = null; //这一句,我已经从逻辑上删掉lis了,大家作证啊
trace ("侦听器还在吗?:"+ lis); //lis也确实指向null了。但你只要继续点击方块,你会发现Click事件仍然被捕捉到。
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
//这个类就是画一个矩形,
class KingdaSprite extends Sprite {
public var nickname:String;
public var ColorNum:uint;
//colorNumber就是#ffcc00这种类型的数,在AS3中推荐用新的uint型来标记它
public function KingdaSprite(colorNumber:uint, nameString:String) {
ColorNum = colorNumber;
nickname = nameString;
graphics.beginFill(ColorNum);
graphics.drawRect(0,0,100,100);
graphics.endFill();
}
}
Listener和As2.0有何不同,和this关键字的“改进了的记忆力”
DOM Level 3中规定的是用Object来做listener。该Object有用来处理事件的方法(method)。
AS3虽然是按照DOM Level 3事件机制设计的,但也不完全听话,有自己独立的想法。在AS3中,侦听器就是函数。也只能用函数来侦听。
其实在ActionScript3中,Function实质也是一种特殊的Object,和AS2.0有相似之处。
见我的文章:
ActionScript高级技巧:深入了解Function
因此AS3.0为什么限定用Function,这和它的架构有关,不细说了。
但有趣的是,在AS3.0中,对IEventDispatcher的定义中,仍然按照DOM3标准用Object来做Listener。见黑羽上一篇教程和随后的评论。
那么问题来了,function中this关键字的指向会怎样?
AS2.0开发者对AS2.0 事件机制中 this关键字的水性杨花应该深有认识。如果用function做侦听器,那么谁发出事件,this就指向谁。这就等于对象之间乱搞关系,啊呀呀。所以MM派了一个Delegate代理警察类来管理。唉,糜乱的岁月不堪回首啊。
//ActionScript 2.0例子:拷贝以下代码到第一帧,拖一个button到舞台,命名为kingda_btn;
function lisFunc() {
trace ("亲爱的,你会指向谁:"+ this.name); //我们本意应当是指向_root;
}
kingda_btn.addEventListener("click", lisFunc); //点一下button,看看指向谁。
回到ActionScript 3.0,来看看坚定的夫妻关系,黑羽总结为:嫁鸡随鸡,嫁狗随狗,什么都不嫁,那就属于global。我靠,读一下,还挺押韵。大家也好记。
简单的解释一下,函数在哪个对象里(应该叫method),那么this就指向谁。不在对象里,那么就指向global。
//【黑羽】ActionScript 3.0系列教程
//http://www.kingda.org
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
public class AddListener extends Sprite {
public function AddListener() {
//用package外面定义的类KingdaSprite创建一个实例,由于同文件中,所以不用import啦
var outsideChild:KingdaSprite = new KingdaSprite(0x00FF00, "outside_sprite");
addChild(outsideChild);//没有了这一句,你啥都看不到。
outsideChild.addEventListener(MouseEvent.CLICK, inclassHandler);//注册类里面的侦听器
outsideChild.addEventListener(MouseEvent.CLICK, outsideHandler);//注册类外面的侦听器
}
private function inclassHandler(event:MouseEvent):void {
trace("类里面的侦听器侦听到MouseEvent事件: " + event);
trace("this关键字指向:"+this);
}
}
}
function outsideHandler(event:MouseEvent):void {
trace("类外面的侦听器侦听到MouseEvent事件: " + event);
trace("this关键字指向:"+this);
}
import flash.display.Sprite;
import flash.events.MouseEvent;
//这个类就是画一个矩形,然后你点击这个矩形会发出标准鼠标click的事件
class KingdaSprite extends Sprite {
public var nickname:String;
public var ColorNum:uint;
//colorNumber就是#ffcc00这种类型的数,在AS3中推荐用新的uint型来标记它
public function KingdaSprite(colorNumber:uint, nameString:String) {
ColorNum = colorNumber;
nickname = nameString;
graphics.beginFill(ColorNum);
graphics.drawRect(0,0,100,100);
graphics.endFill();
}
}







Comments (11)
这几天也看到关于事件这一块来了(英文超菜),对于影片的 onReleaseOutside 事件,按官方的说法是取消了,那么,在AS3中,如何处理那些以前由 onReleaseOutside 处理的事件呢?最典型的就是滑动条的处理。今天尝试了多种方法,总感觉理不清头绪,可否给一个小提示呢?!
Posted by D.Start | August 7, 2006 5:34 PM
Posted on August 7, 2006 17:34
useWeakReference设为了true,等了n久也没回收。。。。你确定试过会回收?
Posted by N神 | August 14, 2006 10:43 AM
Posted on August 14, 2006 10:43
肯定会回收。
回收机制不完全是时间久了就回收,有时是发现资源不够用了,就回收了。
Posted by 黑羽 | August 15, 2006 2:08 PM
Posted on August 15, 2006 14:08
的确感觉回收不完全http://www.akiracasino.net
拿这个帐号登陆试试看
a0290000001:a
这个程序前台全部用Flex2开发的
感觉资源上面回收很差。
内存占用上去了又下来,上去了又下来。但是总体还是在增加。
郁闷,今天正在做调试,看看有没有好的办法。
Posted by Someone | August 21, 2006 4:01 PM
Posted on August 21, 2006 16:01
账号贴错了
a029000001:a
a029000002:a
a029000004:a
a029000009:a
有兴趣的朋友都可以看看。
Posted by Someone | August 21, 2006 4:02 PM
Posted on August 21, 2006 16:02
账号贴错了
a029000001:a
a029000002:a
a029000004:a
a029000009:a
有兴趣的朋友都可以看看。
Posted by Someone | August 21, 2006 4:03 PM
Posted on August 21, 2006 16:03
账号贴错了
a029000001:a
有兴趣的朋友都可以看看。
Posted by Someone | August 21, 2006 4:03 PM
Posted on August 21, 2006 16:03
-,-
怎么发了这么多遍!
发的时候说rename错误,
我就又发了遍
对不起哈
Posted by Someone | August 21, 2006 4:06 PM
Posted on August 21, 2006 16:06
class TextLoader {
private var params_lv:LoadVars;
public function TextLoader() {
params_lv = new LoadVars();
params_lv.onLoad = onLoadVarsDone;
params_lv.load("http://www.helpexamples.com/flash/params.txt");
}
private function onLoadVarsDone(success:Boolean):Void {
_level0.createTextField("my_txt", 999, 0, 0, 100, 20);
_level0.my_txt.autoSize = "left";
_level0.my_txt.text = params_lv.monthNames; // undefined
}
}
如果在3.0。这段代码是不是就可以正常运行?
Posted by oncebet | January 9, 2007 4:34 PM
Posted on January 9, 2007 16:34
flash8中的解释
-------------------
ActionScript 2.0 示例 下面的 TextLoader 类用于加载文本文件,并在文件加载成功后显示一些文本。
// TextLoader.as
class TextLoader {
private var params_lv:LoadVars;
public function TextLoader() {
params_lv = new LoadVars();
params_lv.onLoad = onLoadVarsDone;
params_lv.load("http://www.helpexamples.com/flash/params.txt");
}
private function onLoadVarsDone(success:Boolean):Void {
_level0.createTextField("my_txt", 999, 0, 0, 100, 20);
_level0.my_txt.autoSize = "left";
_level0.my_txt.text = params_lv.monthNames; // undefined
}
}
这段代码无法正确工作,因为在事件处理函数的作用域上存在相关问题,而且 this 的所指也有混淆,无法区分指的是 onLoad 事件处理函数还是类本身。在本示例中,原本预期会出现的行为会在 TextLoader 对象的作用域内调用 onLoadVarsDone() 方法;但实际上是在 LoadVars 对象的作用域中调用的,这是因为该方法已经从 TextLoader 对象中提取出来然后转接到 LoadVars 对象上。在文本文件成功加载后,LoadVars 对象会接着调用 this.onLoad 事件处理函数,然后调用 onLoadVarsDone() 函数,而此时的 this 设置为 LoadVars,而不是 TextLoader。params_lv 对象在调用时位于 this 作用域中,即使 onLoadVarsDone() 函数按照引用依赖于 params_lv 对象,情况也是如此。因此,onLoadVarsDone() 函数需要的是并不存在的 params_lv.params_lv 实例。
要在 TextLoader 对象的范围内正确地调用 onLoadVarsDone() 方法,可以使用以下策略:使用函数文本创建一个调用所需函数的匿名函数。owner 对象在匿名函数的范围内仍然可见,所以可以用它来查找执行调用的 TextLoader 对象。
// TextLoader.as
class TextLoader {
private var params_lv:LoadVars;
public function TextLoader() {
params_lv = new LoadVars();
var owner:TextLoader = this;
params_lv.onLoad = function (success:Boolean):Void {
owner.onLoadVarsDone(success);
}
params_lv.load("http://www.helpexamples.com/flash/params.txt");
}
private function onLoadVarsDone(success:Boolean):Void {
_level0.createTextField("my_txt", 999, 0, 0, 100, 20);
_level0.my_txt.autoSize = "left";
_level0.my_txt.text = params_lv.monthNames; // 一月、二月、三月……
}
}
Posted by oncebet | January 9, 2007 4:38 PM
Posted on January 9, 2007 16:38
我噻,这样学AS真是轻松啊,哈~~~
Posted by slanb | March 10, 2007 5:49 PM
Posted on March 10, 2007 17:49