Posts tagged ‘事件’

I am back

很高兴我有机会说这样的话,不是作为一个全职的程序员,而是作为一个coder。有人说,这有什么区别。我说,有区别,有大区别了。可能是心态放平了吧,没有生存的压力,没有家人的希望。我想,这样的环境,更容易造就一个coder。我们老是羡慕老外,他们有多么好的code环境,他们的公司是多么的自由。可是你想过吗,他们的报酬不是我们中国程序员可比的,他们的国家福利制度也是我们的可比。我们有什么理由抱怨,只能纯“羡慕”而已,就像先辈们憧憬无产主义一样充满敬畏。OK,绝没有鄙视自己的意思。我现在这么讲,不是因为我获得了这样的环境,而是我有了这样的心态。这一切来得不容易,没经历不谈感受。我现在的感受是,我有现在的职业,我很喜欢,我有自己的乐趣,我有code机会,我也很喜欢,这样的人生,说的没出息一点,可以无憾。

UIComponent之currentStateChange事件

在使用State的时候,我总是会选择enterState和exitState事件来处理state切换问题(enterState总是在state切换完毕再抛出,这点很便利),可是最近发现一问题,enterState和exitState实际是抛出FlexEvent对象,此对象不包含上一个state和请求的state的信息,也就是说,你也不会知道你是从哪个state切换过来的,对于某些特别的request来说不是很爽。

于是我查了下UIComponent的源码,发现UIComponent带有两个很好用的事件

  • currentStateChange
  • currentStateChanging

在UIComponent的commitCurrentState方法(private)里,还能找到这两个事件,以及enterState,exitState抛出的顺序:

  1. currentStateChanging
  2. exitState
  3. enterState
  4. currentStateChange

从这里不难发现flex framework对于state的处理机制,首当其冲便是currentState property,它存储着state信息。切换的时候,首先抛出currentStateChanging事件,说明切换开始,然后执行“移除”当前state,抛出exitState(至此state被移除),然后切换到新的state,完成后抛出enterState,接着抛出currentStateChange事件,currentState修改完毕。

并且我们可以注意到,currentStateChange抛出的是StateChangeEvent事件对象,此对象带有oldState和newState property,恰好弥补了enterState和exitState的不足。

AS3事件监听的一个反例

我们都知道,addEventListener和dispatchEvent是一组很经典的事件处理方式,它占据着类之间通信方式的半壁江山。不可否认的是,我们还常常听到这样一个教条:注意removeEventListner。很对,有add就要有remove。只不过一直以来,我都觉得很麻烦,能否自动的remove呢,就像对象的销毁那样,现在都用垃圾处理机制了。

最近就碰到这么个案例,使用socket通信的时候发现,每个事件只需要听一次就够了(这么说吧,通过socket收到的内容当作事件发送到逻辑层,由于某些原因只监听一次就行了)。这样如果还是用add+remove就显得很麻烦。另外我还注意到AS3时间监听的这么一个缺点,比如:

A.addEventListener(Event.A, objA.funcA)

A.call(); // will dispatch Event.A

A.addEventListener(EventA, objB.funcB)

A.call(); // will dispatch Event.A

由于异步的关系,第一次Event.A事件抛出的时候,很可能objA和objB都会收到,而我的原意是,第一个Event.A被objA收到,第二个Event.A被objB收到。

这两种情况下,addEventListener和dispatchEvent的这对组合就不是那么合适了。我的解决方案是,回归到“回调函数”,自定义的话调用一次就能抛弃。拿上面的例子来说,我可以这样定义call函数:

public function call(_callback:Function):void

{

_callback_queue.push(_callback);

//…

}

把回调函数压入队列,用后进先出的方式,等一个事件出来的时候,用_callback_queue.shift()拉出回调函数,这样无论如何都不会混乱了。

change和textinput的区别

在整flex TextArea component的时候,发现这两个事件的解释非常相近,都是针对用户输入的。然后搞了个demo来看看吧:

	<mx:TextArea id="th" x="10" y="156" width="277" height="143">
		<mx:textInput>
			<![CDATA[
				trace("textinput")
				trace(th.text)
			]]>
		</mx:textInput>
		<mx:change>
			<![CDATA[
				trace("change")
				trace(th.text)
			]]>
		</mx:change>
	</mx:TextArea>
	<mx:Button x="10" y="307" label="Button">
		<mx:click>
			<![CDATA[
				th.text += "a"
			]]>
		</mx:click>
	</mx:Button>

第一次打个字进去,一般会看到这样的输出:

textinput

change
w

我猜大概的意思就是textInput事件在property validate之前,而change在之后。后来翻了翻TextArea,原来它们是直接来自textfield的事件,还是textfield对change的解释比较清楚:

Dispatched after a control’s value is modified. Contrast this with the textInput event, which is dispatched before the value is modified. Unlike the W3C DOM Event Model version of the change event, which dispatches the event only after the control loses focus, the ActionScript 3.0 version of the change event is dispatched any time the control changes. For example, if a user types text into a text field, a change event is dispatched after every keystroke. 

总算搞清楚了。其实我最终想在textinput的时候控制某些字母不被输入,研究中…,有知道的朋友希望提点啊。

flex事件监听错误一例 — 容易忽视的闭包对象

先看我的一个例子:

public function set feed(fd:VideoFeed):void
{
	vidFeed = fd;
	JMonitor.getInstance().addEventListener("bic_csv_saved", function(event:Event):void{
		exportBtn.enabled = true;
		exportBtn.label = "Export...";
		Alert.show("Exported file saved successfully");
	});
}

我一直习惯这样的写法(匿名的响应函数),比较简洁,不会在类里添加很多的private方法。但是发现这样的写法有个很致命的问题:如果这个方法被执行多次(我后来把它们移到creationComplete里),那addEventListener也会执行几次,但它容易给人这么一个错觉,响应函数都是同一个。其实不是的,嵌套函数会自动构造一个闭包对象,两次执行addEventListener就会产生两个不同的闭包对象。于是我看到的结果是,Alert执行了好几次,郁闷。使用事件监听的时候一定的小心啊。

让AIR在关闭之前做些收尾工作

AIR跟flex不同,关闭程序之前会抛出CLOSING事件,让你做点事情。本来挺容易的,可是如果事情复杂一点的话,比如弹出个提示框,上传之类需要一点时间的事情,就必须要点非常手段了(因为执行完CLOSING就马上关掉了,哪来的时间给你完成这些工作啊)。下面给出这个非常手段:event.preventDefault(),就能把下面的关闭动作停掉啦。看看解释。

Cancels an event’s default behavior if that behavior can be canceled.

Many events have associated behaviors that are carried out by default. For example, if a user types a character into a text field, the default behavior is that the character is displayed in the text field. Because the TextEvent.TEXT_INPUT event’s default behavior can be canceled, you can use the preventDefault() method to prevent the character from appearing. For example, if a user clicks the close box of a window, the default behavior is that the window closes. Because the closing event’s default behavior can be canceled, you can use the preventDefault() method to prevent the window from closing.

这个方法超有用。我测试了下,点击关闭按钮,代码执行close,电脑的状态栏里右键选关闭都可以触发到CLOSING事件的,但是任务管理器里强关就不会有了。还有一个要注意的是,要有选择的执行preventDefault,不然你只能到任务管理器里关了,为什么自己想吧。