理解共享对象--FlashCom Develop阅读笔记 (七)

2006-03-09 00:37:55

理解共享对象 共享对象可以存储任何Flash支持的数据类型。就存放位置来说,共享对象可以分成存在客户端计算机的本地型,以及存放在服务器上的远程型。你可以用它来记录用户的相关信息(如用户名、性别和其它设置参数等),或者用在服务器端,存储其它联机用户实时分享的信息(如聊天室的内容和线上用户名单等) 共享对象意味着用户可以在不同的用户之间、不同的同一台服务器上的应用程序实体。FlashCom server 支持三种不同的共享对象:Local、remote和server-side。下面简单介绍下这三个共享对象。 本地共享对象(Local shared object) 用于存取本地的数据,存储在用户的计算机硬盘中,并可以在不同的时间被其它应用程序访问。本地共享对象的扩展名为.sol,默认的存储路径是c:\documents and Settings\登录名称\Application Data\Macromedia\Flash Player\服务器网域名称\影片路径\影片文件名.swf\。本地共享对象也可以是短暂的,也就是说只有但应用程序运行时可用。我们也可以不连接Flashcom server而使用本地共享对象。更多的本地共享对象的信息,可以参考手册中的SharedObject.getLocal方法。 建立和存取本地共享对象的方法如下: 1: var so= SharedObject.getLocal('myCookie') //建立本地共享对象 2: //存储资料 3: //注意:不管是读取还是写入资料到本地共享对象,都必须通过data属性。 4: so.data.userName='liu21st'; 5: so.data.msg='世纪流年'; 6: so.data.counter=10; 7: //在默认状态下,以上资料并不会马上写入用户的磁盘,必须等到动画被关闭,或者用户离开你的网站后,才会写入磁盘。如果要立即写入的话,必须使用flush方法。如下: 8: so.flush(); 确认资料是否存储成功可以通过onstatus事件来获取 返回的code值为 SharedObject.Flush.Success(写入成功) SharedObject.Flush.Failed(写入失败) 代码示例: 1: so.onStatus = function (info){ 2: var status=info.code; 3: if (status=='SharedObject.Flush.Success'){ 4: trace('写入成功'); } 5: else trace('写入失败'); 远程共享对象(remote shared object) 通过Flash影片的ActionScript程序,在服务器端建立能让不同联机用户共同存取的资料,称为远程共享对象。和本地共享对象一样,远程共享对象可以被本地计算机存取,不同的是在资料存储在服务器端,所以任何用户都可以连接到远程共享对象访问到相同的信息。默认的存储路径是应用程序实体路径下的sharedobjects文件夹,扩展名是.fso。 远程共享对象也是最常用的共享对象类型。每当联机用户(或服务器端程序)更新远程共享对象的内容,其它联机到相同应用程序实体的用户将自动收到更新内容的事件(onSync),保持彼此资料的同步。聊天室应用程序就是运用这个机制建立的。 例如,你可以打开一个远程共享对象,如电话号码表(在服务器端持久有效)。当用户端对该共享对象作任何更改的时候,修改后的数据对其他连接到该远程共享对象的用户是自同步的。如果因为某种原因,更新了本地的数据信息但是没有连接到服务器,那么所作的更改会在下一次连接到服务器的时候同步远程共享对象。 更多的信息可以参考手册中的SharedObject.getRemote方法。 建立远程共享对象的方法: 1: var client_nc = new NetConnection(); 2: client_nc.connect('rtmp://localhost/videochat/room1'); 3: so = SharedObject.getRemote('records',client_nc.url);//数据资料不写入磁盘 4: so.connect(client_nc); 远程共享对象的数据读取和写入方法和本地共享对象类似,也是通过data属性和flush方法。 使用下面语句可以把数据资料写入服务器端应用程序文件夹共享对象目录 1: so = SharedObject.getRemote('records',client_nc.url,true); 2: 当远程共享对象的内容改变或者初次联机时,它都会向客户端发出onsync (同步)事件,好让所有联机用户都能实时取得最新的共享对象资料。 示例代码: 1: so.onSync = function(list) { 2: for (var k in list) { 3: trace('name = ' + list[k].name + ', event = ' + list[k].code); 4: } 5: // do whatever else you want to do here 6: } 代理共享对象(proxied shared object) 代理共享对象是可以在用户端和服务器端共享的一种远程共享对象,区别在于它是由服务器端的ActionScript程序建立的,例如,在服务器端有两个聊天室的实体chat01和chat02,在chat02中可以连接到在chat01中定义的共享对象,更多的信息可以参考手册的SharedObject.get方法。 和客户端的sharedobject不同,设置共享变量的值要通过 SharedObject.setProperty,取得共享变量的值通过 SharedObject.getProperty 。 实例代码: 1: application.appStart = function() { 2: nc = new NetConnection(); 3: nc.connect('rtmp://' + master_server + '/' + master_instance); 4: proxySO = SharedObject.get('myProxy',true,nc); 5: // Now, whenever the client asks for a persistent 6: // shared object called myProxy they will receive myProxy 7: // shared object from the master_server/master_instance 8: }; 1: myInfo = SharedObject.get('foo'); 2: var addr = myInfo.getProperty('address'); 3: myInfo.setProperty('city', 'San Francisco'); 4: var names = sharedInfo.getPropertyNames(); 5: for (x in names){ 6: var propVal = sharedInfo.getProperty(names[x]); 7: trace('Value of property ' + names[x] + ' = ' + propVal); 8: } 在使用远程共享对象之前,请确认SharedObject.connect 返回 true,在客户端调用SharedObject.flush 方法只是在本地拷贝了一份,要确保服务器端的拷贝,必须在服务器端使用SharedObject.flush 方法,如: 1: // Sample server-side code for flushing a persistent shared object 2: // to the server 3: // Get the shared object when the application is loaded. 4: application.onAppStart = function() 5: { 6: application.mySO = SharedObject.get('SharedObjName', true); 7: } 8: // When a user disconnects, flush the shared object. 9: application.onDisconnect = function(client) 10: { 11: application.mySO.flush(); 12: } 如果在同一时间有多个客户端或者服务器端在同步远程共享对象的话,就会出现问题,要解决这个冲突可以通过下面的方法。 1. 使用不同的位置存储不同用户的信息 这是最简单的一种方法,例如,在聊天室给每个用户不同的位置存放数据,同步只修改自己的数据部分。 2. 分配资料所有者 复杂一点的方法就是定义一个用户为有限的时间内该数据资料的所有者,所有者可以锁定服务器端的共享对象,直到返回可用信息后方可同步另外的数据。下面是示例代码: 通过一个记录游戏最高分的应用程序来说明解决同步冲突的问题,当前系统保存的最高分是95,同时有两个用户打破了这个记录,成绩分别为105和110,如果不锁定最高分的话,两个成绩都会同时执行up&#100;ateHighScore方法,有可能其中一个成绩会无法记录下来。使用锁定共享对象的方法解决了这样一个问题。 1: application.onAppStart = function() 2: { 3: application.scoreSO = SharedObject.get('high_score_so', true); 4: application.scoreSO.onSync = function(listVal) 5: { 6: trace('got an onSync on scoreSO'); 7: } 8: } 9: application.onConnect = function(newClient,name,passwd) 10: { 11: newClient.up&#100;ateHighScore = function(final_score) 12: { 13: application.scoreSO.lock(); 14: if (application.scoreSO.getProperty('high_score_so') < final_score) 15: { 16: application.scoreSO.setProperty('high_score_so', final_score); 17: } 18: application.scoreSO.unlock(); 19: } 20: } 3. 通知客户端 当服务器端收到客户端的同步请求的时候,SharedObject.onSync事件会通知用户端更改被拒绝,然后提供一个用户界面来给用户解决这种冲突。这种技术通常用于客户端不是经常更新的情况。 4. 接受某些,拒绝其它的 应用程序根据“先到先服务”的原则来解决同步的冲突问题。通常需要于客户自己重新请求来解决冲突。 5. 通过send方法来提高控制级别 SharedObject.send 命令给所有连接到该远程共享对象的客户端广播消息,也包括发送者本人。 获取peoplelist值的方法 要获取FlashCom的peoplelist组件的值,可以用下面的方法: 1: yourComponent.people_lb.getValue(); 以上方法可以实现点击用户列表中某人进行相关操作等等~ 设置用户列表组件的颜色 在用户列表组件上按右键选择 edit in place 然后解除people_lb层的锁定,并再次点击右键选择 edit in place 在第一帧的Actionscript底部找到下面这段: 1 : var frogStyle = new FStyleFormat(); 2 : 3 : frogStyle.textColor = '0x666666'; 4 : frogStyle.textSelected = '0x333333'; 5 : frogStyle.textDisabled = '0x333333'; 6 : frogStyle.sel&#101;ction = '0xbefdff'; 7 : frogStyle.sel&#101;ctionUnfocused = '0xd8feff'; 8 : frogStyle.backgroundDisabled = '0xffffff'; 9 : frogStyle.addListener(this); 修改相关的颜色值就可以了 SimpleConnect组件登录的问题 因为默认的SimpleConnect组件并没有验证用户的功能,如果要验证用户的话,可以通过和PHP、ASP等后台程序结合。但是用户名和房间名称怎样带入聊天室呢? 找到simpleconnect组件,在最下面有默认的连接方式 1: this.serverConnect(_parent.username, _parent.appInstance); 含义就是获取上一级(这里就是浏览器传递过来的)的变量,其实我们可以在swf文件后面直接带参数来执行也是可以的,如下: 1: videochat.swf?username=liu21st&appInstance=room1 但是一般不建议这样做,因为这样仍然无法进行程序的验证。 采用的方式可以是用php等后台程序进行验证后(或者在flash文件中调用php来进行验证)后用存入会话 然后在swf的调用方式按照下面方法增加变量(以PHP为例) 1: <PARAM NAME=movie VALUE='Chat.swf'> 2: <PARAM NAME=FlashVars VALUE='username=<?=$_SESSION['UserName']?>&userID=<?= $_SESSION['UID']?>&appInstance=<?=$_SESSION['AppInstance']?>'> 通过这种方式可以传递你需要的变量到flash中,注意不要忘记增加相应的embed标记。 如果不要让用户看到这个传入值,可以把变量存到flash的变量中,然后改变服务器simpleconnect连接参数: 1: this.serverConnect(_root.username, _root.appInstance); 一个简单的聊天系统 用function组件实现一个简易聊天室,大家可以试用下。 私聊组件的命令模式问题 最近在使用中发现 peldi 的私聊组件在执行消息命令的时候,经常会显示出来命令。今天改造了一下,去掉了命令模式,改用按钮的方式来实现清屏、踢人和禁止功能。 实现思路如下:改造peoplelist组件和服务器端的共享变量存储。增加userId、userSex和userIp存储 1: application.user_so.setProperty(clocal.id,{ id:userId,name:username,sex:userSex,ip:userIp }); 在people_lb的listbox组件中同步的时候addItem改成 1: people_lb.addItem(this.data[ i ].name+this.data[ i ].sex,this.data[ i ].ip) 然后在操作的时候先点选用户列表中某个用户,通过getValue() 来去得其IP地址,调用服务器端的相关方法来实现清屏、踢人和禁止功能。 新版视频聊天室测试中~ 今天差不多完成了公司新版视频聊天室的改造工作。 表面上似乎差不多,内部组件重写了不少。 主要改进了: 1 聊天室的管理命令改为按钮形式,避免了经常在聊天记录中显示管理命令的Bug 2 改变私聊方式,增加对某人聊天 3 改变统计在线用户数的方法,避免用户非正常退出的数据库写入问题 4 改进了聊天历史记录文字框的显示方式 不过,目前仍然处于测试阶段,注册免费使用,有兴趣的朋友可以继续关注! 可以从这里进去:[ http://twbbs.idv.to ] 选择左边的聊天室就可以了。 扩展people_list组件 Flashcom自带的people_list组件功能不足,我之前做的聊天室也只是加了用户性别的文本标识,这里讲了有关添加图片的方法 [ 查看 ] fb3有一个实现的方法: [ 点这里查看 ] 其实现方法如下: 1: this.people_lb.setItemSymbol('FPLCustomItem'); 2: globalStyleFormat.textAlign = 'center'; 3: globalStyleFormat.applyChanges(); 在新版的组件中似乎可以用iconFunction 来设置。 SmileyTextField component的问题 SmileyTextField component组件在flashMX2004中发布为flash7的时候,表情符号的显示位置总是在第一行。奇怪的是该组件自带的范例却是运行正常的 。自己做的时候怎么都不行,而且清空的时候也不能正确清除表情图标。研究了一整天,找到了问题所在 在SmileyTextFieldClass.prototype.parseString函数中找到 1: this.line += this.line == undefined? 0: 1; 把它删除或者注释掉 换成下面的代码: 1: if (this.line == undefined) { this.line = 0; } else { this.line +=1; } 才能保证表情符号的位置行正确。 如果不知道SmileyTextField component是什么