2009-08-06 5 views

Répondre

0

Pas vraiment. Sauf si vous écrivez votre propre fonctionnalité pour abandonner après un certain temps, en utilisant un objet Timer (ou mieux, un objet GCSafeTimer, si vous ne le connaissez pas, google le).

1

Je ne vois pas de façon intégrée de le faire. Cependant, il est certainement possible de l'implémenter seul.

Il suffit de créer une classe de transaction représentant chaque appel que vous apportez à une instance de NetConnection. Cette classe de transaction, par exemple "NetTransaction", doit conserver une liste statique privée de toutes les transactions actives et doit stocker la fonction de gestionnaire de résultat dans une variable d'instance privée qui doit être appelée lorsqu'une transaction est terminée (sur résultat, sur l'état, ou sur le délai d'expiration). Notez que ce gestionnaire est unifié, donc il gère toutes sortes de résultats (succès/erreur/délai/annulation). Dans le constructeur de votre classe de transaction, ajoutez "this" nouvelle instance à la liste des transactions actives, démarrez un temporisateur si un timeout non nul est spécifié (en ajoutant un écouteur d'événement pointant sur la fonction cancelTransaction décrite ci-dessous), puis effectuer l'appel réseau en dernier. Lorsque vous terminez une transaction (succès/erreur/délai/annulation), supprimez-la de la liste des transactions actives, annulez le délai d'attente s'il a été défini et transmettez enfin un résultat significatif à la fonction de gestionnaire de résultats.

L'astuce pour que tout cela fonctionne est que vous devez créer des fonctions de gestionnaire de résultat et d'état dans la classe de transaction et transmettre THOSE à votre appel à NetConnection. Ces deux fonctions seront responsables de l'INTERCEPTION du résultat du réseau (résultat ou état), de l'achèvement de la transaction (comme décrit ci-dessus) et de la transmission d'un résultat unifié à la fonction REAL qui a été transmise au constructeur.

Voici les intérieurs dépouillés de la classe NetTransaction de base avec les nécessités de base. Mon implémentation a plus de choses, y compris générer des identifiants de transaction (juste un simple compteur statique, une méthode pour rechercher une transaction active par numéro d'identifiant), des méthodes get/set remplaçables pour l'objet de données de la transaction/Dépaquetage pour les protocoles de données personnalisées dans les classes dérivées de NetTransaction (par exemple WidgetNetTransaction).

static private var active_transactions:Array = new Array(); //active network requests pending a result 
static private var transaction_count:int = 0; //incremented each time a NetTransaction instance is created so each one can have a unique transaction id number assigned to it 

private var transaction_id:int; //Transaction identifier, which may assist a widget in managing its own concurrent transactions. It comes from a static field, auto-incremented in the NetTransaction constructor, so it is always unique for each NetTransaction within the current session... unless more than 2147483648 transactions occur in a single session and the value wraps around, but by then, old transactions wil be forgotten and there shouldn't be any problems as a result. 
private var description:String; //an optional description string to describe the transaction or what it is supposed to do (especially for error-reporting purposes). 
private var request_data:Object; //this stores the data that will be forwarded to your web server 
private var result_handler:Function; //this is the method to be called after intercepting a result or status event. it's left public, because it's acceptable to modifiy it mid-transaction, although I can't think of a good reason to ever do so 
private var internal_responder:Responder; //internal responder attached to the transaction 
private var timeout:int; 
private var timeout_timer:Timer; 

//Constructor 
public function NetTransaction(network_service:NetworkService, request_data:Object, result_handler:Function = null, description:String = null, timeout:int = 0) 
{ 
    //Throw something a little more friendly than a null-reference error. 
    if (network_service == null) 
     throw new ArgumentError("A NetworkService object must be specified for all NetTransaction objects."); 
    if (timeout < 0) 
     throw new ArgumentError("Timeout must be 0 (infinite) or greater to specify the number of milliseconds after which the transaction should be cancelled.\rBe sure to give the transaction enough time to complete normally."); 

    //Save information related to the transaction 
    this.result_handler = result_handler; 
    this.request_data = request_data; 
    this.internal_responder = new Responder(net_result, net_status); //should use override versions of these methods 
    this.description = description; 
    this.timeout = timeout; 
    this.timeout_timer = null; 

    //Grab a new transaction id, add the transaction to the list of active transactions, set up a timeout timer, and finally call the service method. 
    this.transaction_id = transaction_count++; 
    active_transactions.push(this); //transaction is now registered; this is done BEFORE setting the timeout, and before actually sending it out on the network 
    if (timeout > 0) //zero, represents an infinite timeout, so we'll only create and start a timer if there is a non-zero timeout specified 
    { 
     timeout_timer = new Timer(timeout, 1); 
     timeout_timer.addEventListener(TimerEvent.TIMER, this.cancelTransaction, false, 0, true); 
     timeout_timer.start(); 
    } 
    network_service.call(internal_responder, request_data); 
} 


//Finalizes a transaction by removing it from the active transactions list, and returns true. 
//Returns false to indicate that the transaction was already complete, and was not found in the active transactions list. 
private function completeTransaction():Boolean 
{ 
    var index:int = active_transactions.indexOf(this); 
    if (index > -1) 
    { 
     active_transactions.splice(index, 1); 
     if (timeout_timer != null) 
     { 
      timeout_timer.stop(); 
      timeout_timer.removeEventListener(TimerEvent.TIMER, this.cancelTransaction, false); 
     } 
     return true; 
    } 
    else 
    { 
     //Transaction being removed was already completed or was cancelled 
     return false; 
    } 
} 

//An instance version of the static NetTransaction.cancelTransaction function, which automatically passes the transaction instance. 
public function cancelTransaction(details_status_object:Object = null) 
{ 
    NetTransaction.cancelTransaction(this, details_status_object); 
} 

//Cancels all active transactions immediately, forcing all pending transactions to complete immediately with a "NetTransaction.Call.Cancelled" status code. 
static public function cancelAllActiveTransactions(details_status_object:Object) 
{ 
    for each (var transaction:NetTransaction in active_transactions) 
     transaction.cancelTransaction(details_status_object); 
} 

//Cancels the transaction by spoofing an error result object to the net_status callback. 
static public function cancelTransaction(transaction:NetTransaction, details_status_object:Object) 
{ 
    //Build cancel event status object, containing somewhat standard properties [code,level,description,details,type]. 
    var status:NetTransactionResultStatus = new NetTransactionResultStatus(
     "NetTransaction.Call.Cancelled", 
     "error", //cancelling a transaction makes it incomplete, so the status level should be "error" 
     "A network transaction was cancelled. The description given for the transaction was: " + transaction.description, 
     details_status_object, //include, in the details, the status object passed to this method 
     "" //no type specified 
    ); 
    //Call the net_status handler directly, passing a dynamic Object-typed version of the NetTransactionResultStatus to the net_status handler. 
    transaction.net_status(status.ToObject()); 
} 

//Result responder. Override, then call when you're ready to respond to pre-process the object returned to the result_handler. 
protected function net_result(result_object:Object):void 
{ 
    if (completeTransaction()) 
     if (result_handler != null) 
      result_handler.call(null, new NetTransactionResult(this, result_object, null)); 
} 

//Status responder. Override, then call when you're ready to respond to pre-process the object returned to the result_handler. 
protected function net_status(status_object:Object):void 
{ 
    if (completeTransaction()) 
     if (result_handler != null) 
      result_handler.call(null, new NetTransactionResult(this, null, NetTransactionResultStatus.FromObject(status_object))); 
} 

Les classes NetTransactionResult et NetTransactionResultStatus ne sont que de simples classes de données que j'ai mis en place pour obtenir des résultats typées à envoyer à un résultat unifié Il interprète les résultats comme une erreur si NetTransactionResult a une propriété de statut non nul, sinon, il interprète le résultat comme une réussite et utilise les données incluses La classe NetworkService que vous voyez est juste un wrapper autour de la classe NetConnection qui gère le chemin d'appel, gère également tous les événements d'erreur NetConnection de bas niveau, regroupe les messages d'état compatibles avec la classe NetTransaction et appelle enfin cancelAllTransactions. La beauté de cette configuration est que maintenant, peu importe le type d'erreur qui se produit, y compris les délais, votre gestionnaire de résultats pour une transaction sera TOUJOURS appelé, avec toutes les informations dont vous avez besoin pour gérer le résultat (succès/erreur/délai /annulé). Cela rend l'utilisation de l'objet NetConnection presque aussi simple et fiable que d'appeler une fonction locale!

Questions connexes