2009-05-28 13 views
6

Używam biblioteki innej firmy do łączenia się z serwerem za pośrednictwem protokołu asynchronicznego i uzyskiwania odpowiedzi. Na przykład metoda, aby uzyskać identyfikator użytkownika przez nazwę użytkownika wygląda następująco:Potrzebujesz pomocy dotyczącej wywołań zwrotnych i anonimowych klas w Javie

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; 
} 

Problemem jest to, że nie można przypisać zwrócony „wynik” od odpowiedzi serwera do „id_uzytkownika” zmienną od metody (w celu jego powrotu po) . Jak rozwiązać ten problem? Prawdopodobnie mogę przypisać ją do zmiennej pewnej klasy, a nie do metody, ale chcę zachować ją w zasięgu metody, więc nie muszę zajmować się kwestiami współbieżności.

Dzięki.

Odpowiedz

2

Jeśli dobrze rozumiem twoje pytanie, pytasz, jak możesz napisać zmienną z wnętrza anonimowej klasy.

Anonimowe klasy mają dostęp tylko do zmiennych końcowych i nie mogą bezpośrednio "pisać" tych zmiennych.

Prostym rozwiązaniem, które jest "wystarczająco dobre", jest stworzenie rodzaju klasy ValueBox z pojedynczym polem wartości i programem pobierającym i ustawiającym. Możesz wtedy utworzyć nowy w funkcji jako zmienną końcową i mieć dostęp do anonimowej klasy. Klasa anonimowa użyje swojego gettera i settera do zapisu/odczytu.

Fakt, że zmienna jest ostateczna, oznacza, że ​​nie można nanieść odniesienia nigdzie indziej, ale nadal można zmienić zawartość przywoływanego obiektu z dowolnej funkcji.

Większy problem, jaki będziesz mieć, czeka, aż wywołanie zwrotne zostanie wywołane. Ten rodzaj oczekiwania na sen może być wystarczająco dobry, ale warto rozważyć limity czasu, wątki itp. W zależności od tego, co próbujesz osiągnąć.

Co więcej, zakłada się, że nigdy nie nawiążesz połączenia dwukrotnie. W przeciwnym razie musisz podać nam więcej informacji w swoim modelu synchronizacji.

Oto niektóre przykładowy kod:

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

Dzięki. Trzeba go jednak wywołać więcej niż jeden raz ... Jaki model synchronizacji ma na myśli, aby odczytać/zapisać z tego obiektu ValueBox? To będzie dość skomplikowane ... – serg

+0

Problem polega na tym, że możesz mieć wiele wywołań getUserId zanim zdążysz przetworzyć identyfikator użytkownika (np. Wyobraź sobie, że masz 5 wywołań w ciągu pierwszych 100ms). Mógłbyś wtedy mieć problemy z nadpisaniem rzeczy itp. Co chcesz robić w takich sytuacjach? – Uri

+0

Prawdopodobnie nie przetwarzamy kolejnych żądań, dopóki nie zostanie wykonane aktualne. – serg

0

Najprostszą zmianą jest użyć czegoś jak java.util.concurrent.SynchronousQueue. Ale prawdopodobnie sam chcesz udostępnić interfejs oparty na zdarzeniach.

Powiązane problemy