March 19, 2010, 5:06 pm
Flash IDE 可以为调试的swf模拟网速来测试进度条。如果是Flex builder呢,似乎是没有的,不过千万别在这个问题上钻牛角尖,因为这实际上是本地服务器的职责,而不是flex builder该干的工作(flex builder编译完成并启动页面后就结束任务了)。
在这种情况下要为flex模拟慢网速的话,就要使用proxy工具了,我这里推荐ServiceCapture,当然很多http检测工具都带有模拟网速的功能,我选serviceCapture除了它能检测http,还能读出trace和AMF协议,简直是Flash专用工具。
首先你需要安装serviceCapture for firefox 插件,让它“干预”firefox上的调试。


然后所有在firefox里发生的http和AMF连接都会被记录下来,serviceCapture “中转”了firefox的请求,这样就能人为的拖慢网速。

January 27, 2010, 10:39 am
LongLongAgo,在做泡泡龙游戏的时候,发现数据结构的好处。使用树结构的数学模型可以清晰的描述逻辑处理方式。比如在判断是否有球掉落的时候,见下图,就可以用这样的数学语言描述:“对某个球而言,不存在一条路径到达root”。root就是最顶层。

泡泡龙
如果这样的球存在的话,就说明它是“浮空”的,也就是说可以掉下来了。
这类的数学描述在很多领域都用过,记得flash的垃圾回收机制么,原来使用计数法来判断一个对象要不要被消灭,如果用在displayObject树结构里就不够了,因为它们可以相互引用,于是,用上面所说的数学描述就成了很好的补充,跟泡泡龙的原理类似,如果有一个displayObject不能到达root的话,它就脱离了显示树,就该被消灭,而不用管计数是多少。
回到泡泡龙的问题上来,一个被发射上来的球可以看成一个根节点,当它被打到一堆球当中的时候,一个树结构就形成了:以这个新球为根,周围的六个球为第一层子节点(可能某些是空,或者重复应用,需要剔除),然后使用广度优先或者深度优先遍历来查找“通往root的路径”,再加上些优化,就能实现这种数学描述,从而完成“掉落”这个游戏功能。
数学在flash游戏中无处不在。此乃往事,特此笔记。
January 19, 2010, 11:26 am
每次谈到Flex builder和FlashDevelop这两个工具总不免比较一番,其实两者各有优点为什么不互补一下呢。事实上我在实践过程中,觉得有些情况下两个配合着用非常不错。FlashDevelop有轻便的优势,代码提示很好,而Flex builder支持Flex framework,支持可视化开发,搭建UI快捷编码量少。
什么时候配合着用比较好呢。那就是开发AS类库,类库用FlashDevelop开发,轻便快捷,而测试使用Flex builder,快速构建UI来显示效果,提供参考。
通过观察FlashDevelop project的文件夹可以发现,基本上FlashDevelop和Flex builder的布局是差不多的,source code放在src里,编译文件放bin,类库放lib等等。于是就有两种配合方式可供参考:
- 叠在一块儿。先用FlashDevelop建一个project,然后Flex builder也建在同一个位置。
- 分开建project。Flex builder使用external source path来链接类库代码。
显然第二种方式更好,可以有效的将测试代码和类库代码分开。
January 15, 2010, 9:18 am
来自:http://zhudonghua.cto.csdn.net/Article.aspx?Name=zhudonghua&pointid=2046
作者:祝冬华
(非常具有实际意义)
如何面对紧迫项目,如何控制项目的进度?我一直在思考这个问题。
不论积极文化建立的怎么样,不论公司对员工的信任和员工对公司的信任达到什么样的程度,最终的目的就是高质量、高要求、并在可控的时间范围内完成项目。项目带来利润公司才能生存。
然一个现实是:我们所在的软件公司,大多是作坊式企业。有的是令人绝望的管理质量、开发模式和管理层。最可悲的是,管理层的保守性,并且地位不可动摇。于是,营盘是泥塑的,员工是流水的。项目也就变成不可控了。
面对这种情况,只有死马当活马医了。在急迫的项目面前,所有的敏捷开发、CMM、PSP、TSP、RUP、完善的管理开发流程等等都是遥远的事情。所以就近有效的处理才是有效的办法。
第一:文化使之。必须让所有参与者明白,我们是如何的紧迫,项目是如何重要,每个人的作用是如何的关键。大家唯有奋勇杀敌,才能求得生存。通过激发大家的热情,激发士气。
第二:合理使用工具。合理的使用工具,可以使工作事半功倍。例如:版本控制工具SVN,文档编写工具WPS Office 2009(几乎与Word2003一样,而又不收费),脑图工具,Visio,project,bugfree等。
第三:任务部署。项目负责人需要第一时间快速做总体分析,现状汇总,并将任务分解,并用project制作Gantt chart。然后将任务分配下去。做这些工作的基础是充分沟通。
第四:控制项目的进度。项目负责人每天要把项目状态汇总,并及时更新每天的Gantt chart。第二天早上,要一早开项目组短会,并报告项目的进展情况。对于表现突出的成员,要表扬;对于落后的成员,要鼓励。最后,要团结所有项目组成员,将使他们士气高涨。
第五:加强内测。项目开始后,首先要改善测试环境,其次改变大家的测试观念(很多软件开发者,就是把程序跑一遍就认为通过了),使大家做好充分的测试,并及时的发现缺陷并修复。项目达到相应阶段后,要交叉测试。
第六:加强思想工作。对于出现思想或工作未达到要求的人员,一定要做好思想工作。一定要了解他工作未达到要求的原因,并及时帮助解决。最终要的结果是,将落后的工作,及时补回来,并重新高效率工作。
第七:要团结所有项目组成员,千万不要有划分他们,不分彼此。所有人,必须明白:兄弟齐心,其利断金。
第八:要及时安排加班很晚的成员,及时休息。项目负责人,要做好后勤工作。(比如:解决就餐,临时住宿,交通费用等问题,这些问题一定要及时解决)
第九:要及时分享项目阶段性成果。一是成果与总结会议;二是项目组聚餐;三是精神奖励(奖状,小物品,优秀员工等);四是物质奖励,这个视实际条件定。
最后呢,项目必须要成功。
December 30, 2009, 1:04 pm
设计用的辅助工具,官网见这里。我一直用很长时间了,可以很方便的截屏,调色,量尺寸等小活,是辅助Flex/Flash开发的好东东。这里给张截图吧。

这就是它的功能菜单了,包括:
- Screen capture:除了截屏,可以做简单的编辑。不过我一直用Jing,基本上不用它
- Open Color Picker:在屏幕上取色
- Show Color Palette:调色板
December 24, 2009, 10:12 am
新的IronPython 2.6 final版本发布,从语法上已经兼容CPython 2.6,也就是目前用的比较广泛的2.x版本,详细内容见主页。就像主页描述的那样,IronPython有Python的语法,且基于.NET平台运行。它可以用来开发silverlight,以及其它基于.NET平台的东西,而且到目前基本上没有学习障碍了。2.6新特性包括:
This is a major release with improvements across all areas of IronPython. Significant changes include:
- Updating the language and standard library to match CPython 2.6
- Improved .NET integration
- Updating to the latest version of the DLR
- Adding previously missing CPython features and fixing bugs
- Performance improvements in particular startup time improvements
依托强大的.NET平台,silverlight以及今天谈到的IronPython已经展现出强大的发展势头。MS简直如同《星际》里人族机械化部队,连进攻都是组合式的,压迫式的,让人不服都不行。
November 4, 2008, 3:04 pm
我在系统里用了ItemRenderer来显示图片,可是当图片比较多,滚动条来回拉的时候,图片就会反反复复的load进来,浪费了很多网络资源。先来看看我的例子:
<ns1:MyList id="vdList" width="100%" height="100%" variableRowHeight="true" dataProvider="{videoList}" change="selectArticle()">
<ns1:itemRenderer>
<mx:Component>
<mx:HBox width="100%" horizontalAlign="left" verticalAlign="middle" toolTip="{data.toListString()}" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:Image id="thumbnail" source="{data.img}" width="100" height="100"/>
<mx:Text text="{data.toListString()}"/>
</mx:HBox>
</mx:Component>
</ns1:itemRenderer>
</ns1:MyList>
为啥会反复Load呢
为了节约资源,每个ItemRenderer对象都要被重复利用(不然可能占资源过多哦)。比如一个List一开始只显示5个ItemRenderer,它就只生成5个ItemRenderer对象先用着,然后你拖动滚动条滑下去,上面那个“消失”的ItemRenderer对象就会被用到下面来(放新的内容),这就好像履带一样,对象被反复使用。还是回到图片Image上面来,如果是一般文本,放入新的ItemRenderer容器是没有问题的(重新显示一下),如果是图片就麻烦了。要知道Image component本身是有缓存的,它存放着上一张图片,现在那个“消失”的ItemRenderer对象很不辛的被用到了下面当新的容器,载入新的数据,那么图片的URL就变化了,于是它就会重新load新的图片到容器内。ItemRenderer对象被反反复复的装载新数据,就导致了图片被反复load。
我的办法
我首先想到的还是缓存的办法,缓存Image。为了能及时清空缓存,把Image放到dataprovider里托管比较好,这样removeAll的时候也能自动清理干净了。Image和dataprovider捆绑,也能使每次ItemRenderer载入对应的Image,当然Image需要动态的addChild进来了,还要注意addChild之前要检查是不是已经有图片了,需要先清掉。
<ns1:MyList id="vdList" width="100%" height="100%" variableRowHeight="true" dataProvider="{videoList}" change="selectArticle()">
<ns1:itemRenderer>
<mx:Component>
<mx:HBox width="100%" horizontalAlign="left" verticalAlign="middle" toolTip="{data.toListString()}" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:creationComplete>
<![CDATA[
if(data)
{
if(getChildAt(0) is Image)
{
removeChildAt(0);
}
addChildAt(data.img2,0);
}
]]>
</mx:creationComplete>
<mx:show>
<![CDATA[
trace("show")
if(data)
{
if(getChildAt(0) is Image)
{
removeChildAt(0);
}
addChildAt(data.img2,0);
}
]]>
</mx:show>
<mx:Script>
<![CDATA[
import mx.controls.Image;
]]>
</mx:Script>
<!--<mx:Image id="thumbnail" source="{data.img}" width="100" height="100"/>-->
<mx:Text text="{data.toListString()}"/>
</mx:HBox>
</mx:Component>
</ns1:itemRenderer>
</ns1:MyList>
October 6, 2008, 3:03 pm
不管啥语言搞过socket程序的应该知道有个flush命令,意思是将缓存区的数据“刷”走,即通过socket发送出去。可惜在Flex/AS3的XMLSocket类里是没有这个方法的(不晓得它为啥没有),于是在实际应用中便会有点问题。今天碰到顺便来侃侃这个问题。
首先需要搞清楚我们通常用socket到底传些什么东西,从技术上讲,是字符串,再抽象点,可以认为它是自定义指令或者文本。尤其是指令(就是我碰到的),它应该是一条一条分开的,再回到技术层面,它应该是每条指令被独立的“flush”走,如果多条指令被连在一起被一起flush,那就坏事了。
flex/AS3的XMLSocket类很好的封装了底层的socket,并且启用的缓存去存储等待发送的文本或指令,等缓存满或者一定时间(我也没搞清楚具体机制如何)后就flush(这是内部自动执行的,该类没有类似public方法)。于是便有了这么一种情况,如果由一个循环语句,每次循环都向XMLSocket插入一条指令,那么一般XMLSocket不会马上发走,而是可能等循环完毕后一起发送,也就是说指令被连在一起发送了。为了避免这种情况,我写了一个Jbuff类来包装一下XMLSocket
//must use singleton mode
public function Jbuff()
{
Security.allowDomain("localhost");
Security.allowInsecureDomain("localhost");
//TODO: implement function
socket = new XMLSocket();
configureListeners(socket);
connectSocket();
}
///////////////////////////////////////////////////////////
protected var socket:XMLSocket;
protected const APP_PORT:uint = 9012;
protected const SERVER_NAME:String = "localhost";
/*
all msg would be push into [msg_queue]
Jbuff build a loop to send msg from [msg_queue], if it has.
*/
protected var msg_queue:Array = new Array();// message queue
protected var queuer:Timer;
/**
* connect to server
*/
protected function connectSocket():XMLSocket
{
if(!socket.connected)
{
socket.connect(SERVER_NAME, APP_PORT);
}
return socket;
}
protected function configureListeners(dispatcher:IEventDispatcher):void
{
dispatcher.addEventListener(Event.CLOSE, closeHandler);
dispatcher.addEventListener(Event.CONNECT, connectHandler);
dispatcher.addEventListener(DataEvent.DATA, dataHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
}
// connection is closed
protected function closeHandler(event:Event):void
{
if(queuer)
{
queuer.stop();
}
}
// connect successfully
protected function connectHandler(event:Event):void
{
// send msg in a loop
queuer = new Timer(100);
queuer.addEventListener(TimerEvent.TIMER, onSend);
queuer.start();
}
protected function dataHandler(event:DataEvent):void
{
}
protected function ioErrorHandler(event:IOErrorEvent):void
{
}
protected function progressHandler(event:ProgressEvent):void
{
}
protected function securityErrorHandler(event:SecurityErrorEvent):void
{
}
//////////////////////////////////////////////////////////
// send in a loop
protected function onSend(event:TimerEvent):void
{
if(msg_queue.length>0)
{
//get the first one and send
socket.send(msg_queue.shift().toString());
}
}
这里关键就是要把发送时间错开,在类里建立一个队列queue先缓存指令,并每隔0.1秒发送一个。不过这个方法也有一个致命伤,如果指令发送太频繁,就会造成队列太大,指令发送延迟严重。其实如果不怕麻烦,也能用Socket类。
September 16, 2008, 5:03 pm
最近一直在做AIR的项目,顺便结合前面文章来讨论一下各种方案的优缺点。
起因
AIR是一项不错的桌面技术。貌似现在很多公司都在采用AIR了,我估计很多人都是看上了它漂亮的UI吧(确实做的很酷噢,而且相应的开发效率很高)。不过有时候它并不能跟传统的桌面技术相比。我感觉原因有这么几个:
- 缺少各种类库支持。咋一看上去AIR或者Flex的第三方类库还是挺多的,不过注意,它们很多往往还是集中在UI方面,广度不够。
- 不支持系统相关的特性。这是跨系统的通病。看看java就知道。
- 不支持调用系统命令。这估计是最大的硬伤了。
俺最喜欢搞技术混搭了。既然世界上有这么多技术存在,为什么不取长补短,发挥各自优势呢。在分析之前,首先先看看扩展程序将基于一个怎么样的架构:

系统结构图
这是以前的一张图了。它说明了一点,就是扩展程序跟AIR是并行的两条进程,之间通过socket交换命令,一般用户先启动扩展程序,扩展程序再启动AIR。 它的好处在于:低耦合,把AIR不能或不容易做的事情都交给扩展程序,它们之间只要用简单的socket命令就能相互指挥了。我暂时还没有想到更好的方案:)。下面总结一下这个扩展程序要具备哪些特性:
- 扩展性能好,类库多。
- 不用UI。废话,AIR已经是UI了。注意扩展程序完全做为一条没有UI的进程在跑,可以将对普通人它是隐藏的。这里顺便讲个问题,如果有人手动关了怎么办?要知道AIR是可以探测socket的连接情况了,如果关了,没办法,AIR给提示或者一起关了随便你。
- 体积小。有人可能不在乎。AIR runtime for windows 大概10M左右,for linux大概13M,for Mac大概15M。:-),自己衡量吧。我想用户都喜欢精巧的玩意儿吧,至少我是喜欢的。
- 跨平台。桌面技术很难做到跨平台,因为系统相关的特性就不支持了。不过我觉得至少70%可以跨平台就好了,至少为了工作量。
下面分析几个我当时考虑的几种技术:
- C++。这是一个很古老的技术,我最后选的也是它(最老搭配最新,绝配啊)。C++分好多种,为了跨平台,要少用VC等系统相关的API,要多用标准C++的类库,这里非常推荐一下boost类库。这里有人可能认为C++不是跨平台的,要知道C++的设计理念是write once, compile everywhere,只要在各个平台上编译就行了。如果要搭上其它的五花八门的功能,外面也有超多的类库支持。比如我做的录音程序(暂时还没找到跨平台的类库,我估计是没有的)和socket server。总结一下。优点:类库多,性能高,体积小,70%跨平台。缺点:难度比较高,容易出错。
- python。这个东西不是很大众(我喜欢的)。是基于C开发的,跟C++结合的很好,类库也够多,能做到90%跨平台。但是python要一个解释器和基本类库的才能运行的。总结。优点:类库多,性能可以(如果不是要求很高),90%跨平台,融合性非常棒(能调用dll等,跟各种其他技术都能很好配合),快速开发效率高。缺点:体积一般(如果结合解释器和基本类库一起打包大概5M左右),不够大众化。
- java。够普遍了,直接总结。优点:类库多,基本上完全跨平台,够大众化,开发效率高。缺点:完全跨平台(跨多了也不好),性能一般(其实速度可以了,不过JVM一开总要强点内存),体积大(JVM比较大了,这是我直接淘汰它的理由)。
还有一些其他的我不太懂,不过扩展程序不需要UI,这三个基本上够对付了。怎么取舍关键还是看需要。