Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

O’Reilly Programming Flex 2 phần 9 pps
Nội dung xem thử
Mô tả chi tiết
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 application 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 reading 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 performance. 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 example, 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 storage 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 dialog 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. However, you can allow several .swf files to access the same shared object(s) by specifying 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 /. If http://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. However, .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 displays 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 window. 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 authenticates. In a real application, the authentication would be against data from a database, 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;