2011-08-03 32 views
15

leí respuestas de Q similares & UnDiseño modelo para manejar una respuesta asíncrona en Java

How do you create an asynchronous HTTP request in JAVA? | Asynchronous programming design pattern |
AsyncTask Android - Design Pattern and Return Values

Veo muchas soluciones, pero ninguna realmente me satisface.

manera Listener

Una vez que los resultados son capturados, el procesamiento se lleva a cabo en el método onResult.

public interface GeolocationListener { 
public void onResult(Address[] addresses); 
public void onError(Exception e); 
} 

Esta solución no me satisface del todo, porque quiero manejar los resultados en el método principal. Odio esta interfaz porque cuando se devuelve la respuesta, se procesa en onResult, lo que da como resultado cadenas de procesamiento y no hay forma de volver al método "principal".

La forma servlet

public class SignGuestbookServlet extends HttpServlet { 

    public void doPost(HttpServletRequest req, HttpServletResponse resp) 
       throws IOException { 
     // ... 
     resp.sendRedirect("/guestbook.jsp"); 
    } 
} 

no hay ningún código de Java expuesta llamar al servlet. Toda la configuración se realiza en el web.xml

La forma que yo quiero

esperar la respuesta como esta

Response a = getResponse(); 
// wait until the response is received, do not go further 
// process 
Response b = getResponse(); 
// wait until the response is received, do not go further 
process(a,b); 

¿Hay un patrón de diseño para manejar la petición asincrónico y esperar la respuesta como arriba? De otra manera que el oyente. Por favor, no hay biblioteca o marco.

EDIT Gracias hasta ahora las respuestas. No le di la imagen completa, así que expuse la clase de geolocalización Comencé la implementación. No sé cómo implementar el método. ¿Alguien puede mostrar "cómo"? Él (o ella) también debe implementar el oyente para recuperar los resultados

private Address getFullAddress (String text, AddressListener listener, ...){ 

    // new Geolocation(text, listener, options).start() 
    // implements Geolocation.GeolocationListener 
    // how to return the Address from the onResult ? 
} 
+0

Lo que pides en tu edición es fuera de tema. Y el tono es bastante mandón. – toto2

+0

Lo siento, no intenté ser mandón. Acabo de proporcionar más información sobre lo que debe devolver getResponse e implementar también al oyente. Su respuesta ofrece una nueva solución pero es demasiado corta para mí (no implementada con el oyente) para marcarla como la respuesta aceptada. –

+0

@raymondchenon Realmente, cómo hacer algo como esto: dirección privada getFullAddress (texto de cadena, escucha de AddressListener, ...) {--------- Para otra muestra, cuando usamos la biblioteca de Volley, cuando instamos JsonObjectRequest, tiene Overrides onResponse y onError. –

Respuesta

9

El código asíncrono siempre se puede hacer sincrónico. La forma más simple/más cruda es realizar la llamada asincrónica, luego ingrese un ciclo while que solo duerme el hilo actual hasta que el valor regrese.

Editar: Código que convierte una devolución de llamada asincrónica en código sincrónico - de nuevo, una aplicación crudo:

import java.util.concurrent.*; 

public class MakeAsynchronousCodeSynchronous { 
    public static void main(String[] args) throws Exception { 
     final Listener listener = new Listener(); 
     Runnable delayedTask = new Runnable() { 
      @Override 
      public void run() { 
       try { 
        Thread.sleep(2000); 
       } catch (InterruptedException e) { 
        throw new IllegalStateException("Shouldn't be interrupted", e); 
       } 
       listener.onResult(123); 

      } 
     }; 
     System.out.println(System.currentTimeMillis() + ": Starting task"); 
     Executors.newSingleThreadExecutor().submit(delayedTask); 
     System.out.println(System.currentTimeMillis() + ": Waiting for task to finish"); 
     while (!listener.isDone()) { 
      Thread.sleep(100); 
     } 
     System.out.println(System.currentTimeMillis() + ": Task finished; result=" + listener.getResult()); 
    } 

    private static class Listener { 
     private Integer result; 
     private boolean done; 

     public void onResult(Integer result) { 
      this.result = result; 
      this.done = true; 
     } 

     public boolean isDone() { 
      return done; 
     } 

     public Integer getResult() { 
      return result; 
     } 
    } 
} 

También es posible usar un CountDownLatch según lo recomendado por la respuesta de Hakon. Hará básicamente lo mismo. También le sugiero que se familiarice con el java.util.concurrent package para una mejor forma de administrar los hilos. Finalmente, solo porque puede hacer esto no lo hace una buena idea. Si está trabajando con un marco que se basa en devoluciones de llamada asincrónicas, probablemente sea mucho mejor que aprender a utilizar el marco de forma efectiva que tratando de subvertirlo.

+0

¿Puede proporcionar código de muestra? –

0

Si desea un flujo de página en una aplicación web, usted tiene que manejar en el camino web: almacenar algunos datos, ya sea en la sesión, o cookies o campos ocultos, etc.

El problema que intentas abordar, por lo que yo entiendo, no proviene de la asincronía sino del protocolo HTTP sin estado.

Saludos, Stéphane

+0

Bonjour, estoy desarrollando una aplicación para Android. La asincronía es para no arruinar UX en una descarga larga. Nada que ver con el protocolo http sin estado. De todos modos, quiero codificar la "respuesta de obtención" de forma sincronizada. –

1

Esencialmente se necesita un "oyente" de clases no importa qué. Esto se debe a que no sabe CUÁNDO regresará su mensaje de devolución, si es que lo hace (esa es una de las desventajas del procesamiento asincrónico ... qué hacer si no recibe un mensaje de devolución).

Por lo tanto, es necesario implementar un oyente que espere eventos (es decir, el mensaje de respuesta lo impulsa a procesar).

O podría hacer un híbrido sobre eso al tener un hilo separado que "sondea" (o tira) un área de respuesta en su servicio para ver si existe el mensaje de devolución.

Por lo tanto, en realidad se trata de si se desea más un método de "extracción" o "extracción" de la recuperación de mensajes.

El marco SCA (Service Component Architecture) puede ser algo a tener en cuenta, pero dependiendo de lo que esté haciendo, podría ser excesivo también. Pero algo a considerar.

EDIT:

acabo de encontrar esto en las Java SE 6 Javadocs que pueden ser útiles. La interfaz CompletionService que resume lo que importa sobre -> trabajo asincrónico. Te sugiero que eches un vistazo.

6

¿Podría CountDownLatch ayudarle? En el método principal, llama a getResponse y luego countDownLatch.await(). Pasar un recuento de cierre de anclaje al método getResponse y luego contar hacia abajo una vez getResponse el resultado de getResponse está terminado:

CountDownLatch latch = new CountDownLatch(1); 
Response a = getResponse(latch); 
latch.await(); 

latch = new CountDownLatch(1); 
Response b = getResponse(latch); 
latch.await(); 

process(a, b); 

Su getResponse tiene que llamar latch.countDown() una vez que está desincronizado partes devuelven un resultado.

ej .:

public Response getResponse(CountDownLatch latch) { 
    someAsychBloc(final CountDownLatch latch) { 
     do work 
     latch.countDown(); 
    } 
} 
+0

Gracias por CountDownLatch –

11

En primer lugar, no se debe rechazar los dos primeros métodos se discuten. Hay muy buenas razones por las cuales las personas están usando esas técnicas y debes tratar de aprenderlas en lugar de crear otras nuevas.

De lo contrario, usted debe buscar en java.util.concurrent:

ExecutorService es = Executors.newFixedThreadPool(2); 
... 
Future<Response> responseA = es.submit(responseGetter); 
Future<Response> responseB = es.submit(responseGetter); 

process(responseA.get(), responseB.get()); 

donde responseGetter es de tipo Callable<Response> (debe implementar el método public Response call()).

+0

Buena respuesta, he implementado algún código. –

+0

Esta debería ser la respuesta aceptada. Usar Thread.sleep no es una buena práctica. – Rafaesp

Cuestiones relacionadas