Test1:
-
private
var a:Sprite = new Sprite(); -
this.addChild(
a ); -
a不能被回收,因为对象a保持着对它所创建的Sprite对象的引用。
Test2:
-
private
var a:Sprite = new Sprite(); -
this.addChild(
a ); -
a
= null; -
a不能被回收,因为a被addChild到了this的显示列表中,因此this就保持着对a的引用,只清除了变量a对其所实例化的Sprite对象的引用却没有清除this对其的引用
Test3:
-
private
var a:Sprite = new Sprite(); -
this.addChild(
a ); -
a
= null; -
this.removeChild(
a ); -
a能被回收,因为a所创建的Sprite对象不仅从this的显示列表中移除了,还释放了a对其的引用,此时没有任何变量保持着对此Sprite对象的引用了。
从上面三段代码中我们基本上可以理解第一条原则:没有其他对象保持着对其的引用的概念了。但是当你用上数组之后,往往会忽略数组对需要回收的对象的引用,一起来看接下来几个例子:
Test4:
-
private
var a:Sprite = new Sprite(); -
private
var arr: Array = []; -
arr.push(
a ); -
this.addChild(
a ); -
a
= null; -
this.removeChild(
a )
a不能被回收,因为数组arr中还保持着对a所实例化的Sprite对象的引用。为了能够成功地回收a,你还需要将a从数组中剔除:
-
var
index: int = arr.indexOf( a ); -
arr.splice(
index, 1 ); -
或者直接把数组清空:
-
arr
= []; -
//或者arr
= null; -
有了上面的基础之后我们来看一个编码习惯的问题,先看下面两段代码,大家看过后告诉我哪段代码结构更佳。
Code1:
-
private
var a:Sprite = new Sprite(); -
-
public
function show(): void -
{
-
addChild( a ); -
}
-
Code2:
-
private
var a:Sprite; -
-
public
function show(): void -
{
-
if( !a ) -
{ -
a = new Sprite(); -
} -
addChild( a ); -
}
-
Code2的代码结构比Code1的好,为什么?因为变量a只在公共方法show中用到,因此,在Code1中,就算你永远没有调用过show方 法,变量a所实例化的Sprite对象也一直会占据着内存(因为变量a保持着对其的引用),而在Code2中就不存在这个问题,直到需要用到a了才去实例 化之。这是一个较好的编码习惯,还请列位谨记。
接下来我们看看强引用事件侦听对对象垃圾回收的影响,若是一个对象存在强引用事件侦听,则其不会被垃圾回收。看下面的例子:
Test5
-
private
var a:Sprite = new Sprite(); -
this.addChild(
a ); -
a.addEventLitener(
MouseEvent.CLICK, onClick ); -
a
= null; -
this.removeChild(
a ); -
-
private
function onClick( e:MouseEvent ): void -
{
-
trace( "oh, shit!"); -
}
-
a不能被回收,因为有一个鼠标点击的侦听器在其身上。即使你将其从this的显示列表中移去并把a置为了null,你也不过是以为自己闭上眼睛看不见某个东西就以为这个东西不存在了,醒醒吧,少年,别在自己骗自己了。为了顺利回收a,你需要在把a置为null前移除其所有的事件侦听器。
-
private
var a:Sprite = new Sprite(); -
this.addChild(
a ); - a.addEventLitener(
MouseEvent.CLICK, onClick, false, 0, true );//保持第三、四个参数为默认值,设置第五个参数为true - a
= null; - this.removeChild(
a ); -
- private
function onClick( e:MouseEvent ):void - {
-
trace("oh, shit!"); - }
-
a能被回收,因为没有变量保持着对a所实例化的 Sprite对象的引用,且其身上也不具备强引用事件侦听器(由于addEventListener方法最后一个参数被设置为true,因此为a注册的鼠 标点击事件侦听器为弱引用)。但是,虽然弱引用事件侦听器不会妨碍对象的垃圾回收,但是回收速度会被大大减慢,毕竟若引用事件侦听器也是在侦听事件,它肯 定得等待一阵子发现没有动静后才会认为其宿主对象已无用,再去回收。综上所述,若是你的确用不到一个对象了,就手动调用 removeEventListener去移除它的全部事件侦听器吧。
Code1:
- package
- {
-
import flash.display.Sprite; -
import flash.events.Event; -
-
public class Test extends Sprite -
{ -
public function Test() -
{ -
addEventListener(Event.ADDED_TO_STAGE, onAdded); -
} -
-
private function onAdded( e:Event ):void -
{ -
removeEventListener(Event.ADDED_TO_STAGE, onAdded); -
init(); -
} -
-
private function init():void -
{ -
//init something -
} -
} - }
-
Code2:
- package
- {
-
import flash.display.Bitmap; -
import flash.display.Loader; -
import flash.display.LoaderInfo; -
import flash.display.Sprite; -
import flash.events.Event; -
import flash.net.URLRequest; -
-
public class Test extends Sprite -
{ -
public function Test() -
{ -
var loader:Loader = new Loader(); -
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp); -
loader.load(new URLRequest("pigdogwc.jpg")); -
} -
-
private function onComp( e:Event ):void -
{ -
var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo; -
loaderInfo.removeEventListener(Event.COMPLETE, onComp); -
var bmp:Bitmap = loaderInfo.content as Bitmap; -
} -
} - }
-
-
我们看到,那些比较流行的事件,如添加到舞台事件(ADDED_TO_STAGE),加载完成事件(COMPLETE)事实上都是只用一次的事件,在触发事件后我们就可以毫无顾忌地移除事件侦听器了,这是一种良性循环,不会造成内存的不断堆积却找不到问题根源。
-
package
-
{
-
import flash.display.Sprite; -
-
public class A extends Sprite -
{ -
public var aa:Sprite= new Sprite(); -
} -
}
-
package
-
{
-
import flash.display.Sprite; -
-
public class B extends Sprite -
{ -
private var a:A; -
private var b:Sprite; -
-
public function B() -
{ -
a = new A(); -
b = a.aa; -
a = null; -
} -
} -
}
-
-
package
-
{
-
import flash.display.Sprite; -
-
public class MyClass extends Sprite -
{ -
public static var a:Sprite = new Sprite(); -
-
} -
}
-
-
package
-
{
-
import flash.display.Sprite; -
-
public class C extends Sprite -
{ -
public static var c:Sprite = MyClass.a; -
} - }
-
C 类中存在一个变量c持有了MyClass的a变量的引用,类D、E中也存在类似写法,声明了一个或多个变量一直持有着对MyClass.a的引用,那么当 你想回收MyClass.a对象的时候你很容易清理不干净外部的全部对a的引用,比如你把C、D中对MyClass.a的引用置为了null,却忘记了处 理E,只要存在任一个对MyClass.a的引用,其就不会被垃圾回收。因此我们在项目开发过程中必须注意开放成静态变量的对象的数目,且心中一定要清楚 地知道所有对静态变量的引用的地方,以便日后清理。
- package
-
{
-
import flash.display.Sprite; -
-
public class Test extends Sprite -
{ -
-
private var _eventListeners:Object; -
-
public function Test(){} -
-
override public function addEventListener(type: String, listener: Function, useCapture: Boolean= false, priority: int= 0, useWeakReference: Boolean= false): void -
{ -
super.addEventListener(type, listener, useCapture, priority, useWeakReference); -
-
if( !_eventListeners ) -
_eventListeners = new Object(); -
-
//将添加的事件侦听器侦听事件类型以及事件处理函数保存起来 -
_eventListeners[type] = listener; -
} -
-
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void -
{ -
super.removeEventListener(type, listener, useCapture); -
-
if( _eventListeners && _eventListeners[type] ) -
{ -
delete _eventListeners[type];//删除该侦听器记录 -
} -
} -
-
-
public function removeAllEventListener():void -
{ -
for(var event:String in _eventListeners) -
{ -
removeEventListener(event, _eventListeners[event]); -
} -
} -
} - }
-
这段代码应该多少能给你一些启示。不过有少数时候我们可能会给同一个事件添加两个事件侦听器:
- a.addEventListener(
MouseEvent.CLICK, onClick1 ); - a.addEventListener(
MouseEvent.CLICK, onClick2 ); -
那么这样子的话用上面那重载了的addEventListener的代码就无法记录全所有的事件侦听器了,因为在一个Object对象中,一个键只 能对应一个值,当第一次调用addEventListener方法后,_eventListeners[MouseEvent.CLICK] 属性的值等于 onClick1 这个方法,但是第二次调用addEventListener方法后该属性值就会改成onClick2这个方法了,此时onClick1这个侦听器就被漏记 录了。因此,我们需要改写一下记录方式,使用数组来记录全部的事件侦听器:
- package
- {
-
import flash.display.Sprite; -
-
public class Test extends Sprite -
{ -
-
private var _eventListeners:Object; -
-
public function Test(){} -
-
override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void -
{ -
super.addEventListener(type, listener, useCapture, priority, useWeakReference); -
-
if( !_eventListeners ) -
_eventListeners = new Object(); -
-
//将添加的事件侦听器侦听事件类型以及事件处理函数保存起来全部事件侦听函数 -
//都保存在一个数组中,这个数组可以通过_eventListeners[事件类型]来访问 -
if( _eventListeners[type] == null ) -
{ -
_eventListeners[type] = new Array(); -
} -
//防止重复 -
if( (_eventListeners[type] as Array).indexOf(listener) == -1 ) -
{ -
_eventListeners[type].push(listener); -
} -
-
} -
-
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void -
{ -
super.removeEventListener(type, listener, useCapture); -
-
//查询需要移除的事件类型对应侦听器是否存在,若存在则从记录中移除 -
if( _eventListeners[type] != null ) -
{ -
//查询欲移除的侦听函数是否存在于记录中,若存在则移除 -
var index: int = _eventListeners[type].indexOf( listener ); -
if( index != -1 ) -
{ -
_eventListeners[type].splice( listener, 1 ); -
//若一个事件的全部侦听器都移除完毕,则在记录本中将记录该事件的数组移去 -
if( _eventListeners[type].length == 0 ) -
{ -
delete _eventListeners[type]; -
} -
} -
} -
} -
-
-
public function removeAllEventListener():void -
{ -
for(var event:String in _eventListeners) -
{ -
for each(var listener:Function in _eventListeners[event]) -
{ -
removeEventListener(event, listener); -
} -
} -
} -
} -
}
-
- 转载自:http://www.iamsevent.com/post/3.html