存档

2010年2月 的存档

(转)AS3应用程序模块化开发与ApplicationDomain

2010年2月22日 评论已被关闭

原文:http://eidiot.net/2007/06/03/applicationdomain/

当程序越来越大,我们需要把它拆分成多个swf,在需要的时候动态加载。拆分时应该尽量把不同的类编译进唯一的swf,避免因swf文件增多而使整个程序的文件尺寸增大。按此原则可以拆分出以下两种swf,借助 ApplicationDomain 共享其代码和资源。

  • 模块(Module)
    按照程序逻辑,可以拆分出多个“功能模块”,如“注册”、“管理”等等;按照游戏或社区类程序的关卡或场景,可以拆分出不同的“场景模块”。这些模块不是主程序运行必须的,只在需要的时候加载。
  • 运行时共享库(RSL)
    主场景或者多个模块通用的资源,比如位图、声音、设计好的页面元素等,可作为“库”在主程序运行前加载。可以整套更换的皮肤(skin)只需先加载一套。

ApplicationDomain 是存放AS3定义(包括类、方法、接口等)的容器。使用Loader类加载swf时可以通过指定 ApplicationDomain 参数将swf加载到不同的域(Domain):

var loader : Loader = new Loader();
var context : LoaderContext = new LoaderContext();
/* 加载到子域(模块) */
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
/* 加载到同域(共享库) */
context.applicationDomain = ApplicationDomain.currentDomain;
/* 加载到新域(独立运行的程序或模块) */
context.applicationDomain = new ApplicationDomain();
loader.load(new URLRequest("loaded.swf"), context);

ApplicationDomain使用类似于显示列表(DisplayList)的树形结构。 相对于舞台(Stage) ,可以认为 ApplicationDomain 最根部的是系统域(system domain),包含 Flash Player 核心类定义。主程序所在的域(以下简称主域)就是它唯一的子域,类似于Stage下的文档类(Document Class)。
一个fla文档类里代码:

this.stage.addChild(mySprite);
this.addChild(myMC);
this.addChild(myShape);

运行后的显示列表:
01.gif
ApplicationDomain 的类似结构:
02.gif

  • 加载到子域(模块)
    类似于“继承”,子域可以直接获得父域所有的类定义,反之父域得不到子域的。和继承关系不同的是,如果子域中有和父域同名的类,子域定义会被忽略而使用父域的定义。
  • 加载到同域(运行时共享库)
    类似集合里的合并关系。被加载swf里的所有类定义被合并到当前域中可以直接使用。和加载到子域相同,和当前域同名的定义也会被忽略。
  • 加载到新域(独立运行的程序或模块)
    swf载入指定域之前,先要检查该域及其父域中是否存在同名类,重复定义一概忽略。如果加载别人写的程序,或者使用旧版本的主程序加载新版本的模块,为避免类名冲突就要加载到新域独立运行以使用自己的类。

模块加载到同域不是一样可以吗?为何要加载到子域呢?好处就在于,卸载一个加载到子域的模块时,只要确保清除所有到该模块的引用,模块的所有类定义将被垃圾回收(Garbage Collection)。
有两种方式可以访问 ApplicationDomain :

  • ApplicationDomain.currentDomain
    currentDomain是ApplicationDomain的静态变量,表示当前代码所在的域。该变量很奇特,在主程序里指向主域,在加载到子域的模块里则指向该模块所在的子域。虽然 ApplicationDomain 有个 parentDomain 属性,但子域已经自动获得了父域的类定义,所以通过 ApplicationDomain.currentDomain 就可以获取父域定义了——包括主程序和加载到主域的共享库。(注:系统域不可直接访问,主域和所有新域即系统域子域的parentDomain属性为null)
  • LoaderInfo类的applicationDomain属性
    此方式可以访问任何方式加载的swf的 ApplicationDomain。对于主程序来说,加载到同域的库定义已经存在于 ApplicationDomain.currentDomain ,而模块的类主程序一般用不到。所以这种方式个人不推荐使用。

ApplicationDomain 的 hasDefinition() 方法判断某定义是否存在,getDefinition() 方法获取指定的定义。下面以一个 例子 来介绍 ApplicationDomain 的具体用法和应用程序的拆分。
本例 有四个swf,shell.swf是主程序,lib.swf是共享库,login.swf和result.swf分别是“登录”和“结果”模块,所有的视图元件都在共享库中。实际开发时可能有很多库,比如“位图库”、“音效库”、“模型通用库”等。“通用库”里存放多个模块共用的资源,比如此例中的背景元素。而各个模块独有的资源还是放在各自的swf中。
主程序首先将共享库加载到同域,完成后将“登录模块”加载到子域。主程序可以像操作普通的视觉对象(DisplayObject)一样操作加载的模块:监听事件、调用方法。因为编译器不会识别未定义的类,为使用强类型,建议为主类和模型定义相应的接口,使用少量的重复代码协助编程。

private function showModule(p_module : IModule) : void
{
if (this.m_moduleList[0] == "login.swf")
{
p_module.show(this);
p_module.addEventListener("login", this.onLogin);
} else
{
p_module.show(this, this.m_userName);
}
}

模块“继承”了主程序和共享库的所有类和资源,可以通过 ApplicationDomain.currentDomain.getDefinition() 来获取相应的类。注意获取不存在的类会抛出一个 ReferenceError。

protected function getClass(p_name : String) : Class
{
try
{
return ApplicationDomain.currentDomain.getDefinition(p_name) as Class;
} catch (p_e : ReferenceError)
{
trace("定义 " + p_name + " 不存在");
return null;
}
return null;
}

登录模块获取库中的界面元素,并在点击按钮后抛出事件。Event类不允许带参数,必须使用继承Event的自定义事件抛出参数。主程序可以把模块的自定义事件也编译进去(这样就增大了整个程序的文件尺寸),或者让监听模块事件的函数接受一个Objcet参数,以获取其动态属性。

private function onLogin(p_e : Object) : void
{
this.m_userName = p_e.userName;
var login : IModule = p_e.currentTarget;
login.removeEventListener("login", this.onLogin);
login.dispose();
this.loadSwf();
}

主程序收到事件之后卸载注册模块,加载“结果模块”到子域,并将登录模块传出的”userName”参数传给结果模块。

public function show(p_parent : DisplayObjectContainer, … rest) : void
{
var libClass : Class = this.getClass("net.eidiot.appDomainDemo.Libaray");
if (libClass != null) this.initUi(libClass, rest);
}
override protected function initUi(p_libClass : Class, p_rest : Array = null) : void
{
this.addUi(this.getClass(p_libClass.BG_NAME), "结果");
var resultFunc : Function = p_libClass.getResult;
var userName : String = p_rest[0];
this.addChild(resultFunc(userName));
}

注意initUi()方法分别使用了共享库中Libaray类的静态属性BG_NAME和静态方法getResult()。但是直接调用此静态方法会报错,可以先用 resultFunc 变量取出此方法。详细内容请参考 源代码

实例效果演示
下载源文件 (rar 278K)

分类: Flash 标签:

天气预报API

2010年2月21日 评论已被关闭

通过经纬度坐标作为参数执行 Google Weather API, 例如:
http://www.google.com/ig/api?hl=zh-cn&weather=,,,30670000,104019996
(30670000,104019996 为 成都, 中国大陆 的经纬度坐标)

通过城市名称的汉语拼音来查询,例如:以下是北京的天气

http://www.google.com/ig/api?weather=Beijing

分类: Flash Platform 标签: , ,

Flash Player升级至10.0.45.2

2010年2月21日 评论已被关闭
分类: Flash 标签: ,

NBA基于FLASH技术的3d游戏酷站

2010年2月21日 评论已被关闭
分类: Flash 标签: , ,

了解ActionScript的垃圾回收集机制

2010年2月18日 1 条评论

http://www.davidpett.com/actionscript-3-managing-memory/

I have been doing a lot of work in try­ing to min­i­mize mem­o­ry and file size in my flash/ac­tion­script pro­jects, be­cause of the struc­ture of ac­tion­script 3 most of this is a man­u­al pro­cess. One of the first things you can do is when adding an event lis­ten­er, use the op­tion­al pa­ram­e­ters:

_btn.addEventListener(MouseEvent.CLICK, btnClick, false, 0, true);

The last op­tion­al pa­ram­e­ter in the ad­dE­ventLis­ten­er func­tion is useWeakRef­er­ence, which by de­fault is set to false, ac­cord­ing to the Ac­tion­Script 3.0 Doc­u­men­ta­tion, this pa­ram­e­ter “De­ter­mines whether the ref­er­ence to the lis­ten­er is strong or weak. A strong ref­er­ence (the de­fault) pre­vents your lis­ten­er from being garbage-​col­lect­ed. A weak ref­er­ence does not.”

An­oth­er stan­dard that I have ime­ment­ed is to use the RE­MOVED_FROM_STAGE event in every class that I write. In this class I re­move any dis­play ob­jects that I have added and re­move all event lis­ten­ers that those dis­play ob­jects have, be­cause just re­mov­ing an ob­ject does not do this and hose event lis­ten­ers will still be there takin up mem­o­ry and can hin­der per­for­mance.

package
{
    import flash.display.*;
    import flash.events.*;

    public class MyClass extends Sprite
    {
        private var _btn:Sprite;
//———————————–
//    CONSTRUCTOR
//———————————–
        public function MyClass():void
        {
            addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
        }
//———————————–
//    INIT
//———————————–
        private function init(e:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            addEventListener(Event.REMOVED_FROM_STAGE, dispose, false, 0, true);

            _btn = new Sprite();
            _btn.addEventListener(MouseEvent.MOUSE_OVER, btnOver, false, 0, true);
            _btn.addEventListener(MouseEvent.MOUSE_OUT, btnOut, false, 0, true);
            _btn.addEventListener(MouseEvent.CLICK, btnClick, false, 0, true);
            _btn.buttonMode = true;
            addChild(_btn);
        }
//———————————–
//    DISPOSE
//———————————–
        private function dispose(e:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            removeEventListener(Event.REMOVED_FROM_STAGE, dispose);

            if(_btn)
            {
                _btn.removeEventListener(MouseEvent.MOUSE_OVER, btnOver);
                _btn.removeEventListener(MouseEvent.MOUSE_OUT, btnOut);
                _btn.removeEventListener(MouseEvent.CLICK, btnClick);
                try
                {
                    removeChild(_btn);
                }
                catch(e:Error){trace("error: MyClass: dispose: removeChild(_btn): " + e)}
                _btn = null;
            }
        }
    }
}

 

http://dispatchevent.org/mims/creating-weak-references-in-as3/

 

For those of you not familiar with the concept, a weak-reference is a reference to an object that will not hold the linked object in memory when that object is garbage collected.

There are only two ways to create a weak reference in AS3. The first is with the IEventDispatcher.addEventListener() method which allows you to create a weak link between the dispatcher and the listener. To quote the AS3 Bible:

ActionScript 3.0 introduces the concept of weak and strong memory references. Normally, an object will be garbage collected if there are no references to the object. That is, when no objects are using a variable, it gets thrown out. Weak references allow you to reference an object but the object will still be eligible for garbage collection unless another object holds a strong reference to the object. By setting the [addEventListener() method's] useWeakReference flag to true, you will create a weak link between the event broadcaster and the event listener. That way, if an dispatcher is deleted while there are still listeners attached, the weak reference will allow it to be garbage collected. This helps to prevent memory leaks.

The other way is with the objects used as keys in a Dictionary object.

ActionScript, unlike many other languages, does not have a way to explicitly remove an object from memory. Instead it waits until all references to an object are removed and then auto-deletes it. Therefore, an object will continue to stay in memory if all strong references aren’t removed.

Below is an example of how strong-references hold an object in memory. If you’d like to try this out, copy the below text into a file called StrongReferencesExample.as

package {
	import flash.display.Sprite;   public class StrongReferencesExample extends Sprite {
		public function StrongReferencesExample() {
			// create a new object called dog. Add it to the first leash object
			// and make leash2 a copy of leash 1.
			var leash1:Object = new Dog();
			var leash2:Object = leash1;   // tracing both leashes will show that they hold a reference to the Dog
			trace(leash1); // [object Dog]
			trace(leash2); // [object Dog]   // deleting the dog from the first leash will not remove it from the second leash
			// even though we originally set leash2 equal to leash1
			leash1 = null;
			trace(leash1); // null
			trace(leash2); // [object Dog]   // The object (dog) will not be free until all of the references to it (leashes) are broken.
			leash2 = null;
			trace(leash1); // null
			trace(leash2); // null
		}
	}
}
// Define a simple Dog class within the same file.
class Dog {}

Richard Lord over at Big Room Games has an interesting article on hacking AS3 to allow you to create weak-references to objects. The hack is pretty decent but lacks a few things I’d like to see like strong typing at compile-time or a more refined ‘memory manager’ type functionality. However, I tried implementing both of these and came up empty handed. If you can think of a way to make this strong-typed, I’ll give you a candy bar.

Using the WeakReference hack could be useful if you want to make sure that an object will not stay in memory if you forget to delete all references to it. However, keeping track of your objects and practicing good memory management is a much better solution and hacks like this one should be saved for special cases where tracking use of an object becomes difficult or impractical.

Thanks to Alex for the link!

分类: Flash 标签: ,

Adobe AIR 2 Beta 2

2010年2月18日 评论已被关闭
分类: AIR 标签:

免费的桌面图标分类整理工具

2010年2月15日 评论已被关闭
分类: 生活杂谈 标签:

fb4 beta2 sn

2010年2月7日 评论已被关闭

1424-4008-9664-3602-3439-1711

分类: Flex 标签: