1. Trang chủ
  2. » Công Nghệ Thông Tin

O’Reilly Programming Flex 2 phần 9 pps

56 297 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 56
Dung lượng 310,28 KB

Nội dung

Persistent Data | 361 are controlled and managed entirely by Flash Player. These files are called local shared objects, and you can use ActionScript to write to and read from these files. Flash Player uses the flash.net.SharedObject class to manage access to local shared object data. Although the data is stored in files on the client machine, the access to those files is controlled exclusively through the SharedObject interface. This both simplifies working with shared objects and improves security to protect Flex applica- tion users from malicious programmers. Note that the SharedObject class also allows you to work with remote shared objects. For this reason, you may notice that the SharedObject class API includes many properties and methods not discussed in this chapter. Remote shared objects allow real-time data synchronization across many clients, but they also require server software such as Flash Media Server. In this book, we discuss local shared objects, not remote shared objects. Creating Shared Objects Unlike many ActionScript classes, the SharedObject constructor is never used directly, and you cannot meaningfully create a new instance using the constructor. Rather, the SharedObject class defines a static, lazy instantiation factory method called getLocal( ). The getLocal( ) method returns a SharedObject instance that acts as a proxy to a local shared object file on the client computer. There can obviously be many local shared objects on a client computer, so you must specify the specific shared object you want to reference by passing a string parameter to getLocal( ).If the file does not yet exist, Flash Player first creates the file and then opens it for read- ing and writing. If the file already exists, Flash Player simply opens it for reading and writing. The following code retrieves a reference to a shared object called example: var sharedObject:SharedObject = SharedObject.getLocal("example"); Reading and Writing to Shared Objects Once you’ve retrieved the reference to the shared object, you can read and write to it using the data property of the object, which is essentially an associative array. You must write all data that you want to persist to disk to the data property. You can use dot syntax or array-access notation to read and write arbitrary keys and values. In general, dot syntax is marginally optimal because it yields slightly faster perfor- mance. The following writes a value of true to the shared object for a key called hideStartScreen: sharedObject.data.hideStartScreen = true; You should use array-access notation when you want to read or write using a key that uses characters that are not valid for use in variable/property names. For exam- ple, if you want to use a key that contains spaces, you can use array-access notation: sharedObject.data["First Name"] = "Bob"; 362 | Chapter 15: Client Data Communication Data is not written to disk as you write it to the SharedObject instance. By default, Flash Player attempts to write the data to disk when the .swf closes. However, this can fail silently for several reasons. For example, the user might not have allocated enough space or the user might have disallowed writing to shared objects entirely. In these cases, the shared object data will not write to disk, and the Flex application will have no notification. For this reason, it is far better to explicitly write the data to disk. You can explicitly write data to disk using the flush( ) method. The flush( ) method serializes all the data and writes it to disk. If the user has disallowed local data stor- age for Flash Player for the domain, flush( ) throws an error: try { sharedObject.flush( ); } catch { Alert.show("You must allow local data storage."); } The flush( ) method also returns a string value corresponding to either the PENDING or the FLUSHED constants of flash.net.SharedObjectFlushStatus. If the return value is FLUSHED, the data was successfully saved to disk. If the return value is PENDING,it means that the user has not allocated enough disk space for the amount of data the shared object is trying to write to disk, and Flash Player is displaying a settings dia- log to the user, prompting her to allow the necessary allocation. When the user selects either to allow or disallow the allocation, the shared object dispatches a netStatus event. You can listen for the event using the flash.events.NetStatusEvent. NET_STATUS constant: sharedObject.addEventListener(NetStatusEvent.NET_STATUS, flushStatusHandler); The NetStatusEvent type defines a property called info that contains a property called code. The code property will have a string value of either SharedObject.Flush. Success or SharedObject.Flush.Failed. Example 15-3 tries to write to disk. If the user has disallowed local data storage or does not allocate the space when prompted, the application displays an alert. Example 15-3. Shared object example <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)"> <mx:Script> <![CDATA[ import flash.net.SharedObject; import mx.controls.Alert; private var _sharedObject:SharedObject; Persistent Data | 363 By default, Flash Player attempts to allocate enough space for the shared object data. If the shared object is likely to grow over time, Flash Player might prompt the user to allocate more space with each incremental increase. If you know that a shared object will require more disk space in the future, you can preallocate space by calling flush( ) with the number of bytes you want to allocate. For example, the following attempts to allocate 512,000 bytes: sharedObject.flush(512000); The default allocation is 100 KB. Unless the user has changed his Flash Player settings, you can generally assume that you can store up to 100 KB of data in a local shared object without prompting the user. private function initializeHandler(event:Event):void { _sharedObject = SharedObject.getLocal("example"); if(_sharedObject.data.count == null) { _sharedObject.data.count = 20; try { var status:String = _sharedObject.flush( ); if(status == SharedObjectFlushStatus.PENDING) { _sharedObject.addEventListener(NetStatusEvent.NET_STATUS, flushStatusHandler); } } catch (error:Error) { Alert.show("You must allow local data storage."); } } else { Alert.show("Shared object data: " + _sharedObject.data.count); } } private function flushStatusHandler(event:NetStatusEvent):void { event.target.removeEventListener(NetStatusEvent.NET_STATUS, flushStatusHandler); if(event.info.code == "SharedObject.Flush.Failed") { Alert.show("You must allow local data storage."); } } ]]> </mx:Script> </mx:Application> Example 15-3. Shared object example (continued) 364 | Chapter 15: Client Data Communication Controlling Scope By default, every shared object is specific to the .swf from which it originates. How- ever, you can allow several .swf files to access the same shared object(s) by specify- ing a path when calling getLocal( ). The default path is the path to the .swf. For example, if the .swf is at http://www.example.com/flex/client/a.swf, the path is /flex/ client/a.swf, which means only a.swf can access the shared object. For this example, we’ll assume that a.swf retrieves a reference to a shared object called example as follows: var sharedObject:SharedObject = SharedObject.getLocal("example"); If b.swf is in the same directory as a.swf, and b.swf also tries to retrieve a reference to a shared object called example using the exact same code as appears in a.swf, b.swf will retrieve a reference to a different shared object—one that is scoped specifically to the path /flex/client/b.swf. If you want a.swf and b.swf to be able to access the same shared object, you must specify a path parameter using a common path that they both share, such as /flex/client: var sharedObject:SharedObject = SharedObject.getLocal("example", "/flex/client"); In order for .swf files to have access to the same shared objects, they must specify a path that they have in common. For example, both a.swf and b.swf have /flex/client in common. They also share the paths /flex and /.Ifhttp://www.example.com/main. swf wants to use the same shared object as a.swf and b.swf, all three .swf files must specify a path of / for the shared object because that is the only path they have in common. Shared objects can be shared by all .swf files within a domain. How- ever, .swf files in two different domains cannot access the same local shared object. Using Local Shared Objects Thus far we’ve talked about local shared objects in theory. In this section, we’ll build a simple application that uses a shared object in a practical way. This example dis- plays a log-in form in a pop up. However, the user has the option to set a preference so that the application will remember her. This example application uses an MXML component that displays the login win- dow. It also uses a User Singleton class that allows the user to authenticate. Note that in this example, the application uses hardcoded values against which it authenti- cates. In a real application, the authentication would be against data from a data- base, LDAP, or some similar data store. The User class looks like Example 15-4. Persistent Data | 365 The login form component looks like Example 15-5 (name the file LogInForm.mxml and save it in the root directory for the project). Example 15-4. User class for shared object example package com.oreilly.programmingflex.lso.data { import flash.events.EventDispatcher; import flash.events.Event; public class User extends EventDispatcher { // The managed instance. private static var _instance:User; // Declare two constants to use for event names. public static const AUTHENTICATE_SUCCESS:String = "success"; public static const AUTHENTICATE_FAIL:String = "fail"; public function User( ) {} // The Singleton accessor method. public static function getInstance( ):User { if(_instance == null) { _instance = new User( ); } return _instance; } // The authenticate( ) method tests if the username and password are valid. // If so it dispatches an AUTHENTICATE_SUCCESS event. If not it dispatches // an AUTHENTICATE_FAIL event. public function authenticate(username:String, password:String):void { if(username == "user" && password == "pass") { dispatchEvent(new Event(AUTHENTICATE_SUCCESS)); } else { dispatchEvent(new Event(AUTHENTICATE_FAIL)); } } } } Example 15-5. LogInForm.mxml <?xml version="1.0" encoding="utf-8"?> <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.managers.PopUpManager; import com.oreilly.programmingflex.lso.data.User; 366 | Chapter 15: Client Data Communication The application MXML file itself is shown in Example 15-6. // This method handles click events from the button. private function onClick(event:MouseEvent):void { // If the user selected the remember me check box then save the username // and password to the local shared object. if(rememberMe.selected) { var sharedObject:SharedObject = SharedObject.getLocal("userData"); sharedObject.data.user = {username: username.text, password: password.text}; sharedObject.flush( ); } // Authenticate the user. User.getInstance( ).authenticate(username.text, password.text); } ]]> </mx:Script> <mx:Form> <mx:FormHeading label="Log In" /> <mx:FormItem label="Username"> <mx:TextInput id="username" /> </mx:FormItem> <mx:FormItem label="Password"> <mx:TextInput id="password" displayAsPassword="true" /> </mx:FormItem> <mx:FormItem> <mx:Button id="submit" label="Log In" click="onClick(event)" /> </mx:FormItem> <mx:FormItem> <mx:CheckBox id="rememberMe" label="Remember Me" /> </mx:FormItem> </mx:Form> </mx:TitleWindow> Example 15-6. Main MXML file for shared object example <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)"> <mx:Script> <![CDATA[ import mx.containers.Form; import mx.managers.PopUpManager; import com.oreilly.programmingflex.lso.data.User; import com.oreilly.programmingflex.lso.ui.LogInForm; private var _logInForm:LogInForm; private function initializeHandler(event:Event):void { Example 15-5. LogInForm.mxml (continued) Persistent Data | 367 This simple application illustrates a practical use of local shared objects. When you test this example, use the username user and the password pass. // Retrieve the same shared object used to store the data from the // log in form component. var sharedObject:SharedObject = SharedObject.getLocal("userData"); // Listen for events from the User instance. User.getInstance( ).addEventListener(User.AUTHENTICATE_SUCCESS, removeLogInForm); User.getInstance( ).addEventListener(User.AUTHENTICATE_FAIL, displayLogInForm); // If the shared object doesn't contain any user data then display the log in // form. Otherwise, authenticate the user with the data retrieved from the // local shared object. if(sharedObject.data.user == null) { displayLogInForm( ); } else { User.getInstance( ).authenticate(sharedObject.data.user.username, sharedObject.data.user.password); } } private function displayLogInForm(event:Event = null):void { if(_logInForm == null) { _logInForm = new LogInForm( ); PopUpManager.addPopUp(_logInForm, this, true); } } private function removeLogInForm(event:Event = null):void { if(_logInForm != null) { PopUpManager.removePopUp(_logInForm); _logInForm = null; } } ]]> </mx:Script> <mx:TextArea x="10" y="10" text="Application"/> </mx:Application> Example 15-6. Main MXML file for shared object example (continued) 368 | Chapter 15: Client Data Communication Customizing Serialization Many built-in types are automatically serialized and deserialized. For example, strings, numbers, Boolean values, Date objects, and arrays are all automatically serialized and deserialized. That means that even though shared object data is ulti- mately saved to a flat file, when you read a Date object or an array from a shared object, it is automatically recognized as the correct type. Flash Player automatically serializes all public properties (including public getters/setters) for custom types as well. However, Flash Player does not automatically store the class type. That means that when you retrieve data of a custom type from a shared object, it does not deseri- alize to the custom type by default. For instance, consider the class shown in Example 15-7. If you try to write an object of this type to a shared object, it correctly serializes the firstName and lastName properties (getters/setters). That means that when you read the data back from the shared object, it displays those values properly. However, it will throw an error if you attempt to call getFullName( ) because the deserialized Example 15-7. Account class package com.oreilly.programmingflex.serialization { public class Account { private var _firstName:String; private var _lastName:String; public function get firstName( ):String { return _firstName; } public function set firstName(value:String):void { _firstName = value; } public function get lastName( ):String { return _lastName; } public function set lastName(value:String):void { _lastName = value; } public function Account( ) {} public function getFullName( ):String { return _firstName + " " + _lastName; } } } Persistent Data | 369 object will not be of type User. To test this, we’ll use two MXML applications called A and B. A is defined as shown in Example 15-8, and it sets the shared object data. B, shown in Example 15-9 reads the shared object data, and attempts to display the data in alert pop ups. Note that it will correctly display firstName and lastName, but it will throw an error on getFullName( ). Example 15-8. Application A <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)"> <mx:Script> <![CDATA[ import flash.net.SharedObject; import mx.controls.Alert; import com.oreilly.programmingflex.serialization.Account; private var _sharedObject:SharedObject; private function initializeHandler(event:Event):void { _sharedObject = SharedObject.getLocal("test", "/"); var account:Account = new Account( ); account.firstName = "Joey"; account.lastName = "Lott"; _sharedObject.data.account= account; try { var status:String = _sharedObject.flush( ); if(status == SharedObjectFlushStatus.PENDING) { _sharedObject.addEventListener(NetStatusEvent.NET_STATUS, flushStatusHandler); } } catch (error:Error) { Alert.show("You must allow local data storage."); } } private function flushStatusHandler(event:NetStatusEvent):void { event.target.removeEventListener(NetStatusEvent.NET_STATUS, flushStatusHandler); if(event.info.code == "SharedObject.Flush.Failed") { Alert.show("You must allow local data storage."); } } ]]> </mx:Script> </mx:Application> 370 | Chapter 15: Client Data Communication If you want to store the type in the serialized data, you can use flash.net. registerClassAlias( ) . The registerClassAlias( ) function allows you to map the class to an alias. The alias is written to the serialized data. When the data is deserial- ized, Flash Player automatically instantiates the object as the specified type. The fol- lowing revisions to A and B cause the User data to deserialize as a User object. Example 15-10 shows the new A, which creates the User object and saves it to the shared object. Since the code now registers the class to the alias, User, it will store the alias in the serialized data as well. Example 15-9. Application B <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)"> <mx:Script> <![CDATA[ import flash.net.SharedObject; import flash.utils.describeType; import com.oreilly.programmingflex.serialization.Account; import mx.controls.Alert; private var _sharedObject:SharedObject; private function initializeHandler(event:Event):void { _sharedObject = SharedObject.getLocal("test", "/"); try { Alert.show(_sharedObject.data.account.firstName + " " + _sharedObject.data.account.lastName); Alert.show(_sharedObject.data.account.getFullName( )); } catch (error:Error) { Alert.show(error.toString( )); } } ]]> </mx:Script> </mx:Application> Example 15-10. Application A registering a class alias <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initializeHandler(event)"> <mx:Script> <![CDATA[ import flash.net.SharedObject; [...]... (navigator.appName.indexOf("Microsoft") != -1) { return window .Flex2 ; } else { return document .Flex2 ; } } function getDisallowedDates( ) { return [new Date( )] } > . type="text/javascript"> <! function getFlexApplicationReference( ) { if (navigator.appName.indexOf("Microsoft") != -1) { return window .Flex2 ; } else { return document .Flex2 ; } } function getDisallowedDates(. onChange="getFlexApplicationReference( ). setEnabled(this.checked)" /> <object classid="clsid:D27CDB6E-AE6D-11cf -96 B8-444553540000" id=" ;Flex2 " width="175". mx.containers.Form; import mx.managers.PopUpManager; import com.oreilly.programmingflex.lso.data.User; import com.oreilly.programmingflex.lso.ui.LogInForm; private var _logInForm:LogInForm; private

Ngày đăng: 06/08/2014, 08:22