С ростом Flash проекта состоящего из раздельных .swf, соединенных между собой через LocalConnection, может возрасти потребность в размерах передаваемых данных. К примеру, это может быть обмен данными присланных сообщений между игрой и отдельным приложением сообщений.
Проблемы начинаются когда передаваемых данных становится больше 40 Кб, появляется ошибка и приложение перестает нормально работать.
Напомню, что объем данных, которые можно передать как параметры методом send, ограничен 40 килобайтами.
Есть несколько выходов из такой ситуации:
- Использовать Local Shared Objects;
- Передавать данные с помощью JavaScript;
- Передавать данные по LocalConnection разбив на части.
Первые два пункта требуют больших изменений чем последний. Поэтому с минимальными затратами реализуем передачу данных по частям которые будут меньше 40 Кб.
Структура пакета:
- unsigned int — длина данных всего сообщения;
- unsigned int — длина данных объекта;
- данные сериализованного объекта.
Что бы правильно собрать все данные напишем обертку для клиента LocalConnection:
public class ExtendedClient
{
private var receivedData:ByteArray = new ByteArray();
private var length:int = -1;
/** Пользовательский класс - обработчик*/
private var client:Object;
public function ExtendedClient(client:Object)
{
this.client = client;
}
/**
* Метод удаленного вызова.
* @param packet - входящие данные.
*/
public final function reciverLocalConnection(packet:ByteArray):void
{
// Читаем длину всего сообщения
if(length == -1) length = packet.readUnsignedInt();
packet.readBytes(receivedData, receivedData.length, packet.length - packet.position);
// Если необходимое количество данных принять
if(receivedData.length == length)
{
// Обрабатываем полученные данные
deserialization(receivedData);
receivedData = new ByteArray();
length = -1;
}
}
/**
* Десериализаия данных.
* @param receivedData - принятые данные.
*/
private function deserialization(receivedData:ByteArray):void
{
var parameters:Array = new Array();
var temp:ByteArray = new ByteArray();
while(receivedData.position != receivedData.length)
{
receivedData.readBytes(temp, 0, receivedData.readUnsignedInt() - 4);
parameters.push(temp.readObject());
temp.clear();
}
try
{ // Отправляем данные в запрашиваемый мтод
(client[parameters[0]] as Function).apply(this, parameters.slice(1));
}catch(error:ReferenceError)
{
trace("Error:", error.message);
}
}
}
Дальше расширяем стандартный класс LocalConnection, передачу данных будем осуществлять с учетом, размера всех аргументов передаваемых в метод send:
public class ExtendedLocalConnect extends LocalConnection
{
/** Максимальный размер блока данных*/
public static const BLOCK_WEIGHT:uint = 40000;
private var _complete:Boolean = true;
public function ExtendedLocalConnect()
{
super();
}
/**
* Метод отправки данных.
* @param localConnectionName - имя подключения;
* @param args - аргументы, первым должено идти название вызываемого метода.
*/
public final function write(localConnectionName:String, ... args):void
{
_complete = false;
var bytes:ByteArray = new ByteArray();
// Оставляем место для длины данных сообщения
bytes.writeUnsignedInt(0);
// Сериализуем все аргументы
for(var i:int = 0, n:int = args.length; i < n; i++)
{
var startPosition:int = bytes.position;
bytes.writeUnsignedInt(0);
bytes.writeObject(args[i]);
bytes.position = startPosition;
// Записываем длину данных объекта
bytes.writeUnsignedInt(bytes.length - startPosition);
bytes.position = bytes.length;
}
bytes.position = 0;
//Записываем длину данных сообщения
bytes.writeUnsignedInt(bytes.length - 4);
bytes.position = 0;
var bytesLength:int = bytes.length;
var currentPosition:int = 0;
var currentLength:int = bytesLength;
while(currentLength > 0)
{
var packageLength:int = (currentLength > BLOCK_WEIGHT)? BLOCK_WEIGHT: currentLength;
var packet:ByteArray = new ByteArray();
// Формируем пакет данных
bytes.readBytes(packet, 0, packageLength);
currentPosition += packageLength;
currentLength = bytesLength - currentPosition;
if(!currentLength)
_complete = true;
// Отправляем пакет
send(localConnectionName, "reciverLocalConnection", packet);
}
bytes.clear();
}
public function set target(extendedClient:ExtendedClient):void
{
client = extendedClient;
}
public function get complete():Boolean
{
return _complete;
}
}
Поясню зачем нужно свойство complete, при каждой отправке данных метод send создает событие StatusEvent.STATUS. В нашем случае одно сообщение может создавать много таких событий, поэтому что бы определить что сообщение отправлено мы записываем состояние в complete.
Пример использования:
var extendedLocalConnection:ExtendedLocalConnect = new ExtendedLocalConnect();
var client:ExtendedClient = new ExtendedClient(this);
extendedLocalConnection.target = client;
// Для приемника
extendedLocalConnection.connect("myConnection");
// Отправка данных
extendedLocalConnection.write("myConnection", "myFunction", data);
Результат работы приемника
Результат отправки объекта
Таким образом мы можем легко заменить стандартный LocalConnection и обойти ограничение на передачу данных. А в случае когда необходимо использовать и стандартные методы передачи данных, то можно расширить класс ExtendedClient и описать дополнительные методы вызова.
Автор: TALUKS