2009-05-28 15 views
6

J'utilise une bibliothèque tierce pour me connecter à un serveur via un protocole asynchrone et recevoir une réponse. Par exemple méthode pour obtenir userid par nom d'utilisateur ressemble à ceci:Besoin d'aide pour les rappels et les classes anonymes en Java

public int getUserid(String username) { 
     int userid = 0; 

    connection.call("getUserid", new Responder() { 
     public void onResult(final int result) { 
      System.out.println("userid: " + result); 
      //how to assign received value to userid and return it? 
     } 
    }, username); 

    //wait for response 
    while (userid == 0) { 
      try{ 
       Thread.sleep(100); 
      } catch (Exception e) {} 
     } 


     return userid; 
} 

Le problème est que je ne peux pas assignons retourné « résultat » de la réponse du serveur à la variable « userid » de la méthode (afin de le retourner après) . Comment résoudre ceci? Je peux probablement l'assigner à une variable de classe plutôt qu'à une variable de méthode, mais je veux la garder dans la portée de la méthode afin de ne pas avoir à traiter de problèmes de concurrence.

Merci.

Répondre

2

Si je comprends bien votre question, vous demandez comment vous pouvez écrire une variable à l'intérieur d'une classe anonyme.

Les classes anonymes ne peuvent accéder qu'aux variables finales et ne peuvent pas les "écrire" directement.

Une solution simple qui est "assez bonne" est de créer une sorte de classe ValueBox avec un seul champ de valeur et un getter et setter. Vous pouvez ensuite en instancier un nouveau dans la fonction en tant que variable finale et demander à votre classe anonyme d'y accéder. La classe anonyme utilisera son getter et son setter pour écrire/lire. Le fait que la variable soit finale signifie simplement que vous ne pouvez pas pointer la référence ailleurs, mais vous pouvez toujours modifier le contenu de l'objet référencé à partir de l'une ou l'autre de ces fonctions.

Le plus gros problème que vous allez avoir est d'attendre que le rappel ait été appelé. Ce genre de wait-sleep peut être assez bon, mais vous voudrez peut-être considérer les timeouts, threads, etc, en fonction de ce que vous essayez d'atteindre.

En outre, cela suppose que vous n'allez jamais appeler deux fois la connexion. Sinon, vous devez nous fournir plus d'informations sur votre modèle de synchronisation.

Voici quelques exemples de code:

public int getUserid(String username) { 
     final ValueBox<Integer> userid = new ValueBox<Integer>(); 

     connection.call("getUserid", new Responder() { 
       public void onResult(final int result) { 
         System.out.println("userid: " + result); 
         userId.setValue(result); 
         //how to assign received value to userid and return it? 
       } 
     }, username); 

     //wait for response 
     while (userid.isEmpty()) { 
       try{ 
         Thread.sleep(100); 
       } catch (Exception e) {} 
     } 

     return userid.getValue(); 
} 
+0

Merci. Il doit être appelé plus d'une fois si ... Quel modèle de syncronisation voulez-vous dire, lire/écrire à partir de cet objet ValueBox? Cela va être assez compliqué ... – serg

+0

Le problème est que vous pouvez avoir plusieurs appels à getUserId avant de pouvoir traiter l'userId (par exemple, imaginez que vous ayez 5 appels dans les 100 premiers). Vous auriez alors le risque de faire écraser les choses, etc. Que voulez-vous faire dans ces situations? – Uri

+0

Il est probable que vous ne traitiez pas d'autres demandes tant que l'une n'est pas terminée. – serg

0

Le changement le plus simple est d'utiliser quelque chose comme java.util.concurrent.SynchronousQueue. Mais peut-être souhaitez-vous proposer une interface pilotée par les événements?