|
LocalConnectionManager
The LocalConnection Manager supports Flash's LocalConnection system and managing of object types that are passed through the connection.
Phase-Implementation, Phase-Support IntroductionBy default, implementing a local connection requires multiple steps of registering events, proper wrapping of calls in try/catch blocks, and passed sealed Class instances are stripped of their type information when sent over the wire rendering them into generic objects. The LocalConnection Manager is a utility Class that provides a quick way to establish a Flash Player Local Connection and retain type information when passing sealed Class instances over the wire. The BasicsWhen establishing and using a Flash Local Connection for communication, two unique identification values need to be defined: the connection name and the target name. Without these values no application can communicate with another. For example, we have two SWFs that want to connect and communicate with each other: SWF A and SWF B. First, both SWFs need to establish a unique connection name for themselves. This connection name is a unique id that acts like a "home address" for the SWF. Any one that wants to send a message to this SWF must know the connection name. For our example, SWF A is going to assign itself an address (or connection name) as "SWF_A_ADDRESS" and SWF B is going to assign itself an address (connection name) as "SWF_B_ADDRESS". Now, for SWF A to talk to SWF B it needs to know SWF B's address is "SWF_B_ADDRESS", this is the target name for SWF A. SWF B needs to know the address of SWF A, so "SWF_A_ADDRESS" is the target name for SWF B. As you can probably tell, for this to work both SWFs need to know the connection name of the other SWF before it can communicate, so these values need to be established when you create the SWFs. The other requirement of the Local Connection is to have a public method available on the receiving SWF that the calling SWF must know about. In our example both SWF A and SWF B would have a public method called receiveMessage(). When one of the SWFs wishes to send a message to the other, the SWF passes in the target address, the method to call and any parameters required buy the target method. Let's take a look at a simple example: SWF A Example Code public var swfAConnection:LocalConnectionManager;
public function init():void {
// set up our connection
swfAConnection = new LocalConnectionManager(this, "SWF_A_ADDRESS");
// register events
swfAConnection.addEventListener(LocalConnectionEvent.CONNECTION_ERROR, handleLocalConnectionEvent);
swfAConnection.addEventListener(LocalConnectionEvent.SENT_MESSAGE_ERROR, handleLocalConnectionEvent);
swfAConnection.addEventListener(LocalConnectionEvent.STATUS_MESSAGE, handleLocalConnectionEvent);
}
public function sendMessage():void {
// send a message to SWF B
swfAConnection.sendMessage("SWF_B_ADDRESS", "recieveMessage", "SWF A calling SWF B!");
}
public function receiveMessage(message:String):void {
// trace out the message if we receive one
trace(message);
}SWF B Example Code public var swfBConnection:LocalConnectionManager;
public function init():void {
// set up our connection
swfBConnection = new LocalConnectionManager(this, "SWF_B_ADDRESS");
// register events
swfBConnection.addEventListener(LocalConnectionEvent.CONNECTION_ERROR, handleLocalConnectionEvent);
swfBConnection.addEventListener(LocalConnectionEvent.SENT_MESSAGE_ERROR, handleLocalConnectionEvent);
swfBConnection.addEventListener(LocalConnectionEvent.STATUS_MESSAGE, handleLocalConnectionEvent);
}
public function sendMessage():void {
// send a message to SWF A
swfBConnection.sendMessage("SWF_A_ADDRESS", "recieveMessage", "SWF B calling SWF A!");
}
public function receiveMessage(message:String):void {
// trace out the message if we receive one
trace(message);
}Looking at the code you can see that the only real difference between the two SWFs is the connection name they use when they create a new !LocalConnectionManager instance and the target name they use when the SWF calls sendMessage(). By defining a unique address the connection manager can now help broadcast and receive messages via the local connection. One thing to note about the Local Connection, is that only one SWF can connect using a specific connection name. For example, if we have two instances of SWF B running at the same time, whichever instance was the first to connect will be able receive messages on that channel. The second instance to connect will receive no messages from the broadcaster. Retaining Class TypeOne of the powerful things about the Local Connection is that the data serialization/de-serializaton syntax is based on the AMF protocol. These means that if both SWFs have the same Class type reference, the class object instances can be passed back and forth retaining their type. The process of setting up AMF to do this is tedious so the LocalConnectionManager takes care of this process for you. As long as both applications have the same data type then the Class instance will be serialized and de-serialized correctly. For example, we have a User object that we want to pass back and forth between SWF A and SWF B: package com.developmentarc.exmaple {
public class User {
public var firstName:String;
public var lastName:String;
public var id:uint;
}
}Both SWF A and SWF B have references to this class and use it. In this case SWF A will be sending SWF B a user instance: SWF A Example Code import com.developmentarc.exmaple.User;
public function sendUser():void {
// send a user to SWF B
var userInst:User = new User();
userInst.firstName = "Homer";
userInst.lastName = "Simpson";
userInst.id = 3322;
swfAConnection.sendMessage("SWF_B_ADDRESS", "recieveUser", userInst);
}SWF B Example Code import com.developmentarc.exmaple.User;
public function recieveUser(user:User):void {
// do something with the user
trace(user.firstName, user.lastName) //output: Homer Simpson
}If, for some reason, SWF B did not have the matching User object the LocalConnectionManager is smart enough to first check to see if the type exists, if it does not then SWF B will inform SWF A via a LocalConnectionManager Error Event that it did not have the proper class reference. ConsiderationsWith any API/Data set there are always considerations that need to be made when using the technology. Its always better to know about these potential issues before hand, rather then implementing the technology and then realizing it does not behave the way that was originally intended.
|
Wow! This manager is exactly what I was looking for. Thanks so much for developing it and making it available. I was dreading building a similar system.
I have been using the LCM, and its everything I hope for and more... almost. I'm having problems passing a FileReference? object. Any ideas if this is possible with the LCM? Thanks in advance.
Are you passing the FileReference from an AIR app to an AIR app, or is this Flash to Flash, or some kind of mix? In theory this should work but there may be a few issues. The first thing that comes to mind is that the FileReference code may be marked as Transient (its in a package I can't see the code in so I can not verify this). If this is the case this metadata tag would require values to be dropped when serialized. Another issue would be if you are passing AIR to Flash, because I believe the AIR version has more properties, and this may choke on the serialization.
We haven't tested with any of this but my recommendation would be to build a new Object that stores the data that you need, fill this object in from the source FileReference?, pass this new object over the wire, then build another FileReference?. Not elegant, but its the first thing that comes to mind.
Awesome class. Thank you for sharing. Do you have any suggestions for where I can learn more about the the limitations of passing data via the LocalConnectionManager? Specifically, what kind of objects can be serialized and deserialized?
One place to start would be Darron Schall's post about Transient metadata. This is what inspired me to build the LCM a few years back. Outside of that, I don't know of any resource off the top of my head, but I would recommend getting more familiar with the AMF protocol and the general limitations/ability of Local Connection. Darron has some great links to the the livedocs that cover this topic.
Thinking about your question, my first tip would be: objects that require constructor parameters are not going to deserialize properly. What you are essentially doing with the deserialization is creating a new instance of an object and then populating its values with the values from the serialized data. The problem is that if your constructor expects values and deserialization cannot provide them. So when passing data around, make sure your constructor either has no arguments or has default values that are acceptable when constructed.
Another thing to throw out there is the 40k size limit the the Flash Local Connection system imposes. We just hit this issue on a project that DevelopmentArc? is working on. We were trying to pass references of UI components around, which of course, is a bad idea. The problem is that UI components are massive object with tons of self-references, sub-children and references to other massive objects such as the SystemManager. The way we solved this was the same way I recommended A.Rolelk fix his FileReference issue. We created a custom object that represents the UI Component, but only at the top level (no child objects are passed over the wire).
If we need to get more information, such as accessing one of the child objects, we would then make a call back to the source app for another flat representation of the child object. The actual solution is a lot more complex then this, we wrote a parser that dynamically generated the properties we wanted by using Flash's description API, but the general solution is that we don't pass over the entire object, we just pass limited representations of the object that we can use as a starting point.
So far those have been the biggest application development hurdles we have had with LCM, as you (and we) find more issues please feel let us know so that we can help improve the documentation and the utility.
This sounds like a great utility. How does it handle large objects though? I'd like to store images and sounds in one swf and pass them through the LCM to another. Does it handle the amortization of large objects correctly? Or, perhaps, is there a way of increasing this 40k size limit?
The LCM currently does not support file/data management, this is one feature we have been looking at but at the moment it hasn't been as high a priority for the 1.0 release as other features. We are definitely seeing and hearing more use cases for this kind of support and will look at it post 1.0 for sure.
The 40k limit is a Flash Player limit and one that can be adjusted or changed. This means that the only way to support large files is by breaking them down into smaller chunks and then sending them over to be reconstructed.
One of the challenges with this kind of feature is how to properly break up, send over and then reconstruct large data sets. On top of this we need to look at data call order, data integrity validation, preventing recursive self-referencing, and other potential issues. We will need to solve this before we release a new build of the LCM, more then likely this will be an extension of the LCM system.
Thanks for asking about this and if you develop a solution that you would like to share before we take this feature on please let us know!
不错
How does this work with https connections?