使用 HTML 5 创建 Flex 的离线应用程序

IBMdW 发布于 2011/06/11 09:29
阅读 712
收藏 1

本文转自 IBM developerWorks

简介: 目前 HTML 5 技术大兴其道,很多厂商都开始围绕着 HTML 5 技术在开发下一代 Web 应用。难道 HTML 5 真的会终结当前同样火热的 RIA 技术吗? 事实上二者完全可以结合起来使用,从而共同增强 Web 应用程序,提高用户体验。例如,关于离线存储这一重要特性,HTML 5 中的 localstorge 就是用来支持这一特性的。 Flex 这一 RIA 技术在离线存储方面并没有标准实现,但是我们可以通过整合 HTML 5 这一特性,从而创建 RIA 的离线应用。 本文首先会简要介绍 HTML 5 中的 localstorge,然后通过实例来介绍如何在当前的 Flex 应用中和 HTML 5 技术进行整合,从而使用 HTML 5 技术创建 Flex 的离线应用程序。

离线存储简介

互联网已经日益成为应用程序开发的默认平台,提供了传统胖客户端模型(C/S Client/Server)的替代模型,基于浏览器服务器(B/S Browser/Server)的瘦客户端模式应用程序开始占据主流位置,Web 的广泛使用解决了 C/S 应用程序部署和更新的困难。基于浏览器的瘦客户端应用程序是在 Web 服务器上部署和更新的,因此消除了将应用程序的任何部分显式部署到客户计算机并加以管理的必要性。但瘦客户端应用程序也存在一些缺点:

  • 由于采用了 HTML 页面形式的用户界面,客户端的数据处理能力较 C/S 应用程序有所下降,用户体验也相对糟糕,无法像 C/S 那样使用丰富的效果来展示数据。
  • 浏览器必须总是具有网络连接,这意味着用户在断开连接时将无法访问应用程序,当再次连接后,必须重新输入数据,这就降低应用程序的可用 性。由于应用程序的大部分逻辑和状态位于服务器上,因此瘦客户端会频繁地向服务器发回数据和处理请求。浏览器必须等待响应到达,然后用户才能继续使用该应 用程序,因此,Web 应用程序的响应速度较之 C/S 应用程序慢很多。这个问题在低带宽或高延迟的情况下进一步恶化,并且产生的性能问题可能导致应用程序可用性和用户效率大幅度下降。

RIA 技术的出现使得在客户端和服务器端进行更好的平衡,RIA 使用相对健壮的客户端描述引擎,能够提供响应速度快和图形丰富的用户界面,而快速的响应需要提升数据获得的速度作为支撑。本文研究基于 Flex 的离线存储,通过在客户端直接存储数据,可加速 Web 应用程序的响应。

HTML5 离线存储

HTML5 草案的前身名为 Web Application 1.0, HTML5 的目标是保持和当前 HTML 标准 HTM L4.01 以及 HTML 的 XML 版本 XHMTL1.0 向后兼容。HTML5 规范仍然在演化之中,提到的新特性很多,下面是对这些新特性的简要说明:

  • 新的布局元素,包括日历控件、地址卡、标尺和进度条
  • 视频、音频的支持,包括 Ogg、MPEG4 等格式的支持
  • Web 存储,提供在客户端存储数据的新方法

HTML5 提供了两种在客户端存储数据的新方法:

  • localStorage -- 没有时间限制的数据存储
  • sessionStorage -- 针对一个 session 的数据存储

HTML5 存储为 Web 站点提供了在本地计算机上存储和提取数据的方法,之前这些都是由 Cookie 机制完成的,但是 Cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 Cookie 速度很慢而且效率不高。在 HTML5 中,数据不是由每个服务器请求传递的,而是只有在请求时使用数据。它使在不影响网站性能的情况下存储大量数据成为可能。对于不同的网站,数据存储于不同的 区域,并且一个网站只能访问其自身的数据。HTML5 使用 JavaScript 来存储和访问数据。

首先要检测浏览器是否支持 HTML5 存储,如果支持,在全局变量 window 上会有一个名为 localStorage 的属性;如果不支持,则这个属性是未定义的,使用如下的 API 来检测:

typeof(localStorage) == 'undefined'

注意 JavaScript 是对大小写敏感的,localStorage 是混合大小写的。

各浏览器对 HTML5 存储的支持如下:

IE Firefox Safari Chrome Opera iPhone Android 8.0+ 3.5+ 4.0+ 4.0+ 10.5+ 2.0+ 2.0+

HTML5 存储是基于键值对的,用被命名的 key 来存储数据,并以同样的 key 来取得这个数据。Key 的类型为 string,而存储的数据可以是任何 JavaScript 支持的类型,包括 string, Boolean, integer, 或者 float。 然而,数据的存储实际上还是 string,如果需要存储或提取任何非 string 类型的数据,则需要显示地调用诸如 parseInt(),parseFloat() 等函数将数据转换为 JavaScript 期望的数据类型。

目前标准的 HTML5 存储也有一些限制需要注意,它的大小上限为 5M,如果超过这个限制将会抛出“QUOTA_EXCEEDED_ERR”的异常,这个需要时刻注意。不过相对于 string 类型来说,5M 已经是不小的存储容量。

HTML5 localStorage API

localStorage 按照 HTML5 的规范,实现了 DOM Storage 接口,存储的是键值对结构,API 有:

· getter any getItem(in DOMString key): 返回 key 对应的 value,如果 key 不存在则返回 null,而不是抛出异常;

· setter creator void setItem(in DOMString key, in any data):在 localStorage 中添加 <key, data> 键值对,如果 key 存在则更新 key 对应的 value 值;

· deleter void removeItem(in DOMString key):从 localStorage 中删除键为 key 的 item,如果 key 不存在则什么都不做;

· void clear():删除 localStorage 中所有的键值对;

· readonly attribute unsigned long length:返回 localStorage 中所有键值对的个数;

· getter DOMString key( int unsigned long index):返回 index 对应的 key,如果 index 不在 [0, length-1] 的范围内,则返回 null。

localStorage 的存储状态可以在 Chrome 浏览器内置的开发工具(工具 -- 开发人员工具 --Storage--localStorage)中看到,在 Chrome v7.0.517.44 中可以看到 localStorage 的存储状态如下:


存储状态

Flex 技术

RIA 是集桌面应用程序的最佳用户界面功能与 Web 应用程序的普遍采用和快速、低成本部署以及互动多媒体通信的实时快捷于一体的新一代网络应用程序。目前比较成熟的几种 RIA 客户端开发技术包括 Adobe Flash/Flex,Laszno,Dojo,Microsoft 的 Avalon。

Adobe Flex 是为满足希望开发 RIA 的企业级需求而推出的表示服务器和应用程序框架,它可以运行于 J2EE 和 .NET 平台。Flex 表示服务器在应用服务器内运行,提供基于标准的、声明的标称方法和流程,并提供运行时服务、应用程序整合和管理功能。Flex 整合的能力可以轻松地通过 Web 服务、Java 对象访问或 XML 使用现有的代码及信息,用于开发丰富客户端应用程序的表示层。应用程序设计基于 Flex UI 组件库及基于 XML 的 MXML 来定义丰富的用户界面,利用面向对象的脚本语言(ActionScript)来处理程序逻辑,由 Flex 服务器翻译成 SWF 格式的客户端应用程序,在 Flash Player 中运行。结合了声音、视频和实时对话的综合通信技术使 RIA 具有前所未有的网上用户体验,具有高度互动性和丰富的用户体验。

本文将基于 HTML5 的 localStorage 建立一个 Flex 的 sample 应用。

一个入门的例子 - Flex 应用和 HTML5 localStorage 结合

前面介绍了 HTML5 离线存储中 localStorage 的特点和 API,下面将选择 Flex 作为表现层来展现我们的示例程序,以进一步了解 HTML5 离线存储中 localStorage 的应用。

本示例在 Flex 的 MXML 中通过 ExternalInterface 调用 JavaScript 代码来实现 HTML 页面标题的改变:

清单 1. WrapperCaller.mxml

 <?xml version="1.0"?> 
 <!-- wrapper/WrapperCaller.mxml -->  <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> 
  <mx:Script> 
     import flash.external.*; 
  
     // 用于改变页面的标题
     public function callWrapper():void { 
        var s:String; 
        if (ExternalInterface.available) { 
         var wrapperFunction:String = "changeDocumentTitle";             /* 这里调用 ExternalInterface 的静态方法 call 来调用 HTML 页面中 Javascript 的方法
             *changeDocumentTitle,这个方法有两个参数,分别为 key.text, val.text 
             */ 
         ExternalInterface.call(wrapperFunction,key.text,val.text);         } else { 
           trace("Wrapper not available"); 
        } 
     } 
     
     // 用于删除 localStorage 所有的键值对
     public function callRemove():void 
     { 
     	 if(ExternalInterface.available) 
     	 { 
   var wrapperFunction:String = "remove";             /* 这里调用 ExternalInterface 的静态方法 call 来调用 HTML 页面中 Javascript 的方法
           *remove,这个方法不带参数              */ 
     		 ExternalInterface.call(wrapperFunction); 
     	 } 
     	 else 
     	 { 
     		 trace("Wrapper not available"); 
     	 } 
   }   </mx:Script> 
  
  <mx:Form > 
     <mx:FormItem label="Key:"> 
        <mx:TextInput id="key"/> 
     </mx:FormItem> 
     <mx:FormItem label="Value:"> 
     	 <mx:TextInput id="val" enter="callWrapper()"/> 
     </mx:FormItem> 
  </mx:Form> 
  
 <!-- 两个按钮,分别用来改变页面的标题,和删除 localStorage 所有的键值对 -->   <mx:Button label="Change Document Title" click="callWrapper()"/> 
  <mx:Button label="Remove All Local Storage" click="callRemove()"/> 
 </mx:Application> 

这里有两个 Button,一个用于改变页面的标题,另一个用于删除 localStorage 所有的键值对。

注意到函数 callWrapper 和 callRemove 中都有 ExternalInterface.call 方法的调用,这个函数是类 ExternalInterface(flash.external.ExternalInterface)的 static 方法,用来调用 JavaScript 函数,它的原型为:

call(functionName:String, ... arguments):*

其中 functionName 为 JavaScript 中的函数名称,可以传递也可以不传递参数给名字 functionName 对应的方法。在本例中 changeDocumentTitle 方法有两个参数,而 remove 方法则没有参数。


清单 2. WrapperBeingCalled.html
				 
 <html><head> 
 <title>WrapperBeingCalled.html</title> 
 </head> 
 <body scroll='no'> 

 <SCRIPT LANGUAGE="JavaScript"> 
    // 对应于 MXML 中的 callWrapper 方法,改变页面的标题
    function changeDocumentTitle(a,b) 
    { 
          // 判断浏览器是否支持 HTML5 的 localStorage 
    	 if(typeof(localStorage) == 'undefined') 
    	 { 
 alert('Your browser does not support HTML5 localStorage. Try upgrading.'); 
  } 
    	 else 
    	 { 
    		 try 
    		 { 
                            // 调用 localStorage 的 setItem 函数,将键值对存储于 localStorage 中
    			 localStorage.setItem(a,b); 
				 if(localStorage.getItem(a)!=null) 
				 { 
                                     // 从 localStorage 中提取数据,用于修改页面标题
    				 window.document.title = localStorage.getItem(a); 
    				 alert("Page Title has been changed"); 
				 } 
    			
    		 } 
    		 catch(e) 
    		 { 
    			 if(e == QUOTA_EXCEEDED_ERR) 
    			 { 
    				 alert('Quota exeeded!'); 
    			 } 
    		 } 
    	 } 
        
    } 
    
    // 对应于 MXML 中的 callRemove 方法,删除 localStorage 中存储的所有键值对
    function remove() 
    { 
    	 if(typeof(localStorage) == 'undefined') 
    	 { 
    alert('Your browser does not support HTML5 localStorage. Try upgrading.'); 
    } 
    	 else 
    	 { 
    		 try 
    		 { 
                            /* 将 localStorage 中所有的键值对删除,并检查 localStorage 的长度判断
                             * 是否所有的键值对都已经删除,如果是则提示用户已删除
                             */ 
    			 localStorage.clear(); 
    			 if(localStorage.length==0) 
    			 { 
        			 alert("All items have been removed successfully"); 
    			 } 
    		 } 
    		 catch(e) 
    		 { 
    			 if(e == QUOTA_EXCEEDED_ERR) 
    			 { 
    				 alert('Quota exeeded!'); 
    			 } 
    		 } 
    	 } 
    } 
    
 </SCRIPT> 

 <h1>Wrapper Being Called</h1> 
 <table width='100%' height='100%' cellspacing='0' cellpadding='0'> 
    <tr> 
        <td valign='top'> 
            <object id='mySwf' classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' 
 codebase='http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab'
            height='200' width='400'> 
                <param name='src' value='WrapperCaller.swf'/> 
                <param name='flashVars' value=''/> 
                <embed name='mySwf' src='WrapperCaller.swf' 
                pluginspage='http://www.adobe.com/go/getflashplayer' 
                height='100%' width='100%' flashVars=''/> 
            </object> 
        </td> 
    </tr> 
 </table> 
 </body></html> 

这里对应的有清单 1 中提到的两个方法:changeDocumentTitle 和 remove。changeDocumentTitle 首先检查浏览器是否支持 HTML5 中的 localStorage 属性,不支持的情况下提示用户浏览器不支持 HTML5,支持的情况下,先将得到的 key/value 存储到 localStorage 中,然后从 localStorage 中提取 key 对应的 value 来改变页面的标题,改变后提示用户标题已改变;remove 方法也一样先判断浏览器是否支持 HTML5,然后调用 localStorage 的 clear() 方法,之后判断 localStorage 的长度是否为 0,如果为 0,表示已经清楚了所有的键值对,则提示用户所有的存储都已删除。


图 1. 用户界面
图 1. 用户界面

图 2. 改变页面标题后的界面
图 2. 改变页面标题后的界面

标题被改变,并有提示弹出


图 3. 改变页面标题后 localStorage 的存储状态
Figure xxx. Requires a heading

图 4. 删除 localStorage 中所有键值对
图 4. 删除 localStorage 中所有键值对

查看 localStorage 的存储状态如下


图 5. 删除 localStorage 中所有键值对后的存储状态

图 5. 删除 localStorage 中所有键值对后的存储状态

结束语

本文 介绍了 HTML5 的 localStorage 特点,以 Flex 作为表现层介绍 localStorage 的应用,涉及到 Flex 对 JavaScript 方法的调用,对于大规模应用的开发尚需深入研究,通过本文的介绍,相信可以帮助你快速的了解 localStorage 和 Flex 的结合开发。

加载中
返回顶部
顶部