AS3 CookBook学习整理(十四)
1. 清除视频显示
调用Video对象的clear()方法
在调用netStream.close()以后,并不会自动清除video显示的内容。视频的最后一帧内容仍显示在Video对象上,需调用video.clear()来进行清除
要从现实列表上删除Video对象需调用removeChild(video)
2. 检测用户带宽
Flash播放器并没有内建带宽检测系统,要想测出用户带宽,需要通过Flash播放器下载一个文件(如JPEG文件),通过下载的大小和所花的时间可以计算出平均下载速度,根据8个比特等于1个字节,1000个字节等于1个kilobyte(kb),转换公式为:
kilobits(KB) = bytes /1000 * 8;
package { import flash.display.Sprite; import flash.events.Event; public class Sample0625 extends Sprite { public function Sample0625() { var bandwidthTester:BandwidthTest = new BandwidthTest( ); bandwidthTester.addEventListener(Event.COMPLETE, onBandwidthTest); bandwidthTester.test( ); } private function onBandwidthTest(event:Event):void { trace(event.target.detectedBandwidth); } } } import flash.events.EventDispatcher import flash.net.URLLoader; import flash.net.URLRequest; import flash.events.Event; import flash.utils.getTimer; internal class BandwidthTest extends EventDispatcher { private var _downloadCount:uint; private var _bandwidthTests:Array; private var _detectedBandwidth:Number; private var _startTime:uint; public function BandwidthTest() { _downloadCount = 0; _bandwidthTests = new Array( ); } public function get detectedBandwidth( ):Number { return _detectedBandwidth; } // Run the bandwidth test. public function test( ):void { // Use a URLLoader to load the data. var loader:URLLoader = new URLLoader( ); // Use a URL with a unique query string to ensure the data is // loaded from the server and not from browser cache. var request:URLRequest = new URLRequest("Test.jpg?unique=" + (new Date( )).getTime( )); loader.load(request); loader.addEventListener(Event.OPEN, onStart); loader.addEventListener(Event.COMPLETE, onLoad); } // When the file starts to download get the current timer value. private function onStart(event:Event):void { _startTime = getTimer( ); } private function onLoad(event:Event):void { // The download time is the timer value when the file has downloaded // minus the timer value when the value started downloading. Then // divide by 1000 to convert from milliseconds to seconds. var downloadTime:Number = (getTimer( ) - _startTime) / 1000; _downloadCount++; // Convert from bytes to kilobits. var kilobits:Number = event.target.bytesTotal / 1000 * 8; // Divide the kilobits by the download time. var kbps:Number = kilobits / downloadTime; // Add the test value to the array. _bandwidthTests.push(kbps); if(_downloadCount == 1) { // If it's only run one test then run the second. test( ); } else if(_downloadCount == 2) { // If it's run two tests then determine the margin between the // first two tests. // If the margin is small ( in this example, less than 50 kbps) // then dispatch a complete event. If not run a test. if(Math.abs(_bandwidthTests[0] - _bandwidthTests[1]) < 50) { dispatchCompleteEvent( ); } else { test( ); } } else { // Following the third test dispatch a complete event. dispatchCompleteEvent( ); } } private function dispatchCompleteEvent( ):void { // Determine the avarage bandwidth detection value. _detectedBandwidth = 0; var i:uint; for(i = 0; i < _bandwidthTests.length; i++) { _detectedBandwidth += _bandwidthTests[i]; } _detectedBandwidth /= _downloadCount; // Dispatch a complete event. dispatchEvent(new Event(Event.COMPLETE)); } }
3. 使用SharedObject存储信息
ActionScript中,SharedObject类实现了客户端机器数据的持久性存储。有两种类型的共享对象:本地和远程
本地 -- Local Shared Objects(LSOs)
远程 -- Remote Shared Objects(RSOs)
Flash的LSOs就如同Web浏览器中的cookies,它们被一些开发者称为"超级cookies",因为LSOs可以存储大量数据,且存储和读取的都是原生的ActionScript数据类型
LSOs默认的空间大小100KB,用户可以通过Flash Player's Settings Manager控制LSOs的使用空间大小。存储在客户端的LSO文件是一种二进制文件,扩展名为.sol,同一个域的Flash电影通过flash.net.SharedObject类读写.sol文件
当.sol文件创建后,被放置在Flash播放器对应的应用程序数据目录
Windows XP: For Web sites -- C:\Documents and Settings\<user>\Application Data\Macromedia\Flash Player
\#SharedObjects\<random code>\<domain>\<path>\<object name>.sol For AIR Applications -- C:\Documents and Settings\<user>\Application Data\<AIR Application Reverse Domain Name>
\Local Store\#SharedObjects\<flash filename>.swf\<object name>.sol Windows Vista/2008: C:/Users/username/<user>/AppData/Roaming/Macromedia/Flash Player/#SharedObjects/<domain>/<path>
/<flash filename>.swf/<object name>.sol
SharedObject类的静态方法getLoal()用于创建或打开共享对象,它至少需要一个参数指明共享对象名称:
var example:SharedObject = SharedObject.getLocal("myOption");
getLocal()方法首先试图定位找到LSO,如果找不到则根据这个名字创建新的,否则就返回SharedObject实例
SharedObjects对象有个内建的属性data,data属性类型为object,因此可以添加任何信息(不能存储可视化对象,如Sprite,TextFields)
package { import flash.display.Sprite; import flash.net.SharedObject; public class Sample0625 extends Sprite { public function Sample0625() { var shareObj:SharedObject = SharedObject.getLocal("myOption"); shareObj.data.name = "hxw"; shareObj.data.gameList = new Array("wow","war3","dota"); shareObj.data.loginTime = new Date(); shareObj.data.newObj = {age:"23",city:"shenzhen",msn:null}; } } }
4. 保存SharedObject对象(Flush)
以下几种情况会导致Flash自动试图保存LSO数据到硬盘上:
* 当Flash播放器关闭时
* 当SharedObject对象被垃圾回收时
* 当调用SharedObject.clear()、SharedObject.close()方法时
如果需要立即保存共享对象数据,我们可以显式调用SharedObject.flush()方法:
var flushResult:String = sharedObject.flush(minDiskSpace)
参数minDiskSpace为必须分配给此对象的最小磁盘空间,单位为字节,默认为0
当flush()方法触发时,它试图把数据写到客户端上,调用结果有三种(flushResult的返回值):
SharedObjectFlushStatus.FLUSHED -- 成功保存
SharedObjectFlushStatus.PENDING -- 显示对话框,要求用户增加磁盘空间量以供此域中的对象使用
抛出Error -- 用户拒绝存储或Flash播放器因某种原因导致存储失败
PS: 为了避免返回PENDING,请为minDiskSpace传递一个值
package { import flash.display.Sprite; import flash.events.NetStatusEvent; import flash.net.SharedObject; import flash.net.SharedObjectFlushStatus; public class Sample0625 extends Sprite { private var example:SharedObject; public function Sample0625() { example = SharedObject.getLocal("example"); example.data.someData = "a value"; var flushResult:String = ""; try { flushResult = example.flush( ); if ( flushResult == SharedObjectFlushStatus.PENDING ) { //当用户做出选择后,netStatus事件被激活,需要定义一个事件处理函数,当事 //件处理函数被触发时,传递进一个类型为flash.events.NetStatusEvent的事件, //检查info.code属性值判断用户是同意(SharedObject.Flush.Success)
//还是拒绝(SharedObject.Flush.Failed) example.addEventListener( NetStatusEvent.NET_STATUS, onStatus ); } else if ( flushResult == SharedObjectFlushStatus.FLUSHED ) { //存储成功 } } catch ( e:Error ) { //这里代表用户的本地存储设置为'Never',可以在这里弹出一个设置框让用户修改 //Security.showSettings( SecurityPanel.LOCAL_STORAGE ); } finally { trace(example.data.someData); trace(flushResult); } } private function onStatus(event:NetStatusEvent):void { if (event.info.code == "SharedObject.Flush.Success" ) { //用户选择了同意 } else if (event.info.code == "SharedObject.Flush.Failed" ) { //用户选择了拒绝 } //只需要监听一次,所以移除掉该事件监听 example.removeEventListener( NetStatusEvent.NET_STATUS, onStatus ); } } }
5. 删除SharedObject里保存的数据
用delete删除data集合中的某个属性,或使用clear()方法清除整个共享对象(即删除了.sol文件)
package { import flash.display.Sprite; import flash.net.SharedObject; public class Sample0626 extends Sprite { public function Sample0626() { var obj:SharedObject = SharedObject.getLocal("jay"); obj.data.name = "hxw"; obj.data.pwd = "millfox"; obj.data.game = "wow"; for(var str1:String in obj.data) { trace(str1 + ":" + obj.data[str1]); } delete obj.data.pwd; trace("----------------------"); for(var str2:String in obj.data) { trace(str2 + ":" + obj.data[str2]); } obj.clear(); trace("----------------------"); for(var str3:String in obj.data) { trace(str3 + ":" + obj.data[str3]); } } } }
name:hxw
game:wow
pwd:millfox
----------------------
name:hxw
game:wow
----------------------
6. 使用SharedObject存储自定义类实例
LSOs使用特殊的二进制格式,Action Message Format(AMF),当要在LSO中存储类实例时,实例会被编码为包含属性的普通的object。这样当重新从共享对象中读取实例时,已经不是原来的类实例了,因为已不能根据类型信息解码回来
解决方法是调用flash.net.registerClassAlias("classAliasName",ClassName)
package { import flash.display.Sprite; import flash.net.SharedObject; import flash.net.registerClassAlias; public class Sample0703 extends Sprite { public function Sample0703() { registerClassAlias("hxw.class.person",Person); var shareObj:SharedObject = SharedObject.getLocal("userInfo"); if(shareObj.data.person == undefined) { var obj:Person = new Person("胡晓伟",27); shareObj.data.person = obj; } else { delete shareObj.data.person; } trace(shareObj.data.person is Person); //trace(shareObj.data.person.toString()); } } } internal class Person { private var _name:String; private var _age:int; public function Person(name:String,age:int) { _name = name; _age = age; } public function toString():String { return _name + " is " + _age + " years old"; } }
7. swf文件之间共享LSO数据
默认情况下,LSOs存储的名称是唯一的,这主要是为了防止名称冲突(不同swf生成的sol文件,会在以这个swf命名的文件夹下)
如果要让同一个域中的多个swf文件能访问同一个LSO,可以指定SharedObject.getLocal("example","/")的第二个参数
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.net.SharedObject; import flash.text.TextField; public class Sample0703 extends Sprite { private var shareObj:SharedObject; private var textBox:TextField; public function Sample0703() { shareObj = SharedObject.getLocal("clickRate","/"); if(shareObj.data.clickNumber == undefined) { shareObj.data.clickNumber = 0; } textBox = new TextField(); this.addChild(textBox); stage.addEventListener(MouseEvent.CLICK,onClick); } private function onClick(event:MouseEvent):void { shareObj.data.clickNumber += 1; textBox.text = shareObj.data.clickNumber; } } }
8. 让用户设置LSO的空间大小
使用Security.showSettings(SecurityPanel.LOCAL_STORAGE)弹出对话框,让用户自定义大小
9. 同一台电脑的多个swf文件通信(LocalConnection)
分为发送端(Send)和接收端(Receive)
发送端LocalConnection.send("_myChannel", 'receiveMethod');
接收端LocalConnection.connect("_myChannel");
若不想在send()方法中指定域名,但要向Flash Player指出接收方和发送方LocalConnection对象不在同一个域中,可在connect()和send()调用中的连接名之前加一个下划线"_",这样Flash Player不会加入域信息,如果不是以下划线开头,则通信信道名称字符串将被自动转换成domain:connectionName,而不管是本地域还是远程域
同一个域
// receivingLC is in http://www.domain.com/receiving.swf receivingLC.connect('myConnection'); // sendingLC is in http://www.domain.com/sending.swf // myMethod() is defined in sending.swf sendingLC.send('myConnection', 'myMethod');
具有可预知域名的不同域
// receivingLC is in http://www.domain.com/receiving.swf receivingLC.allowDomain('www.anotherdomain.com'); receivingLC.connect('myConnection'); // sendingLC is in http://www.anotherdomain.com/sending.swf sendingLC.send('www.domain.com:myConnection', 'myMethod');
具有不可预知域名的不同域
// receivingLC is in http://www.domain.com/receiving.swf receivingLC.allowDomain('*'); receivingLC.connect('_myConnection'); // sendingLC is in http://www.anotherdomain.com/sending.swf sendingLC.send('_myConnection', 'myMethod');
发送端代码:
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.StatusEvent; import flash.net.LocalConnection; public class MySender extends Sprite { public function MySender() { stage.addEventListener(MouseEvent.CLICK,onClick); } private function onClick(event:MouseEvent):void { var localConn:LocalConnection = new LocalConnection(); localConn.send("_myChannel","showGame","World Of Warcraft"); localConn.addEventListener(StatusEvent.STATUS,onStatus); } private function onStatus(event:StatusEvent):void { trace(event.level); } } }
接收端代码
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.net.LocalConnection; import flash.text.TextField; public class MyReceiver extends Sprite { private var textBox:TextField; private var localConn:LocalConnection; public function MyReceiver() { textBox = new TextField(); this.addChild(textBox); stage.addEventListener(MouseEvent.CLICK,onClick); } private function onClick(event:MouseEvent):void { localConn = new LocalConnection(); localConn.allowDomain("*"); localConn.connect("_myChannel"); localConn.client = this; } public function showGame(str:String):void { textBox.text = str; } } }
PS: 还有个与allowDomain( )类似的方法allowInsecureDomain( )方法,大多数情况下这两种方法是一样,不同点在于HTTPS的使用上,当flash来自于HTTPS,其里面的本地连接实例不能和来自于HTTP的flash通信,除非使用allowInsecureDomain( ),默认下HTTP 和HTTPS 的flash是不能通信的,即使是在同一个域。并不推荐使用allowInsecureDomain( ),这样可能会带来不安全因素
10. Loader与URLLoader的区别
Loader -- 读取swf、图片(jpg、png、gif)
URLLoader -- 文本文件(xml、php、jsp...)
Loader加载过来的数据类型:
如果加载图片文件(jpg,gif,png等)时,Loader.content得到数据类型是Bitmap对象;
如果加载SWF文件(flash 9 版本)时,Loader.content得到数据类型是MovieClip对象;
如果加载SWF文件(flash 9 以前版本) 时, Loader.content得到数据类型是AVM1Movie对象;
Loader是给它的contentLoaderInfo属性增加事件,而不是给Loader对象增加事件:
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
URLLoader是给它自己增加事件:
xmlLoader.dataFormat=URLLoaderDataFormat.TEXT;
xmlLoader.addEventListener(Event.COMPLETE,xmlLoaded);