2014-04-23 11 views
7

Jak synchronizować żądania RoboSpice? Czy to możliwe? Chciałbym użyć RoboSpice w IntentService.Jak synchronizować żądania RoboSpice?

Edit:

Od czasu do czasu przychodzi konieczność wykonywania coś synchronicznie np czynny. W moim ostatnim projekcie muszę kolejkować różne typy żądań i chciałem użyć IntentService z RoboSpice. W moim przypadku, gdy wykonuję różne żądania, muszę poczekać na wyniki z request1, a następnie przesłać dane z niego do request2 i wykonać je.

Chcę mieć kolejkę żądań wsadowych. Powiedzmy, że mamy dwa typy żądań: request1 i request2. request2 potrzebuje danych pobrane przez request1:

  1. wykonać request1
  2. czekać
  3. uzyskać dane pobrane przez request1 i przekazać do request2
  4. wykonać request2
  5. czekać
  6. goto 1.

Chciałem użyć IntentService (kolejki), ale umiera po uruchomieniu żądania z powodu async.

Moim zdaniem używanie słuchaczy lub CountDownLatch nie jest najlepszym sposobem.

+0

Mam ten sam problem, nad nim zbyt :( – Eefret

Odpowiedz

7

Zgodnie z propozycją Riccardo Ciovatti on the RoboSpice mailing list, bezpośrednią odpowiedź na Twoje pytanie brzmi:

final CountDownLatch latch = new CountDownLatch(1); 

final YourRequest request = new YourRequest(); 
spiceManager.execute(request, new RequestListener<YourResponse>() { 

    @Override 
    public void onRequestFailure(SpiceException spiceException) { 
     latch.countDown(); 
    } 

    @Override 
    public void onRequestSuccess(YourResponse response) { 
     latch.countDown(); 
    } 
}); 

latch.await(); 

Ale to nie jest dobry idiom używać, chyba że jest wykonywany w wątku tła. Przetwarzanie asynchroniczne jest istotną cechą RoboSpice; utrzymuje wątek interfejsu użytkownika.

+0

I edytowane moją odpowiedź – Ziem

+0

Nowe pytanie nie jest o synchronizacji życzenie, ale jak je łańcuch na tym.. case, wykonaj drugą prośbę od odbiorcy pierwszego: – Snicolas

+0

@Snicolas Szukałem prostego sposobu na wykonanie żądania RoboSpice synchronicznie i niechętnie zdecydowałem się na ten wzorzec.Jeżeli widzę, że to omawiałem, to zignoruj ​​to jako prawidłowe wymaganie z powodu blokowania wątku UI, ale co jeśli nie wykonujesz go z wątku UI, w moim przypadku chciałbym to zrobić w metodzie 'performFiltering' w' Filtrze' .Ta metoda jest wykonywana z wątek roboczy, więc nie ma potrzeby odciążania wykonywania t o usługa. Wydaje się niepotrzebne obciążenie. – darnmason

1

Korzystanie z RoboSpice w IntentService. Rozwiązał problem za pomocą CountDownLatch. Powiedzmy, że mamy 2 różne SpiceManagers i niektóre metody SyncMethod, aby wykonać sekwencję w IntentService.

Globals:

private final SpiceManager aSpiceManager = 
     new SpiceManager(ASpiceService.class); 
private final SpiceManager bSpiceManager = 
     new SpiceManager(BSpiceService.class); 

private CountDownLatch handleIntentLatch; 

onHandleIntent: Przed wykonujemy syncMethodA - my init, nasz CountDownLatch z 1. Po wykonaniu syncMethodA oczekujemy() do odliczania() na naszej zatrzask. Kiedy później jakiś sposób wywoła countDown() na naszym zatrzasku co najmniej raz - metoda onHandleIntent będzie kontynuować jego wykonywanie i zakończenie, co spowoduje wywołanie zwrotne IntentService onDestroy().

@Override 
protected void onHandleIntent(Intent intent) { 
    handleIntentLatch = new CountDownLatch(1); 

    syncMethodA(); 

    try { 
     handleIntentLatch.await(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

syncMethodA(): Załóżmy, że chcemy uruchomić kilka metod synchronizacji w sekwencji (syncMethodA który zwrotna wykonuje syncMethodB etc).

private void syncMethodA() { 
    SpiceRequest requestA = new SpiceRequest(); 

    if (!aSpiceManager.isStarted()) { 
     LogUtils.LOGD(TAG, "starting aSpiceManager"); 
     aSpiceManager.start(getApplicationContext()); 
    } 

    aSpiceManager.execute(requestA , new RequestListener<ResponseA>() { 
     @Override 
     public void onRequestSuccess(final ResponseA responseA) { 
      // SOME LOGIC 

      syncMethodB(); 

      // SOME LOGIC 

     @Override 
     public void onRequestFailure(SpiceException spiceException) { 
      handleIntentLatch.countDown(); 
      // SOME LOGIC 
     } 
    }); 
} 

syncMethodB, syncMethodC etc są takie same - w onRequestSuccess rozpoczynamy następny syncMethodX. W dniu onRequestFailure możemy countDown() nasz zatrzask (handleIntentLatch).

Bardzo ważne !!! W ostatniej syncMethodX w kolejności (po której zakończenie chcemy metoda onHandleIntent kontynuować to wykonanie i wykończenie, które spowodują IntentService powstrzymać) - my odliczanie() nasz zatrzask w onRequestSuccessTAKŻE.

onDestroy: tutaj zatrzymujemy naszych SpinceManagers.

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    LogUtils.LOGD(TAG, "onDestroy"); 
    shutDownSpiceManagers(); 
} 

shutDownSpiceManagers:

private void shutDownSpiceManagers() { 
    if (aSpiceManager.isStarted()) { 
     LogUtils.LOGD(TAG, "stopping aSpiceManager"); 
     aSpiceManager.shouldStop(); 
    } 
    if (bSpiceManager.isStarted()) { 
     LogUtils.LOGD(TAG, "stopping bSpiceManager"); 
     bSpiceManager.shouldStop(); 
    } 
} 

Wszystko powinno być OK teraz: nie wyciekły Kontekst, SpiceManagers zostanie zabity w onDestroy i dopiero po wywołania zwrotne są rozwiązane.

0

Jeśli nie chcesz dokładnie wykonywać synchronizacji, ale chcesz, aby żądania były wykonywane sekwencyjnie w dowolnej kolejności, możesz napisać własną, prostą klasę, która po prostu wykona żądanie B, gdy żądanie A zakończy się pomyślnie lub zakończy się niepowodzeniem. W ten sposób: https://github.com/Deepscorn/Shared/blob/master/app/src/main/java/com/gamelift/shared/request/base/RequestSequenceExecutor.java. Więc kod będzie wyglądać następująco:

sequenceExecutor.setRequest(new FirstRequest()); 
sequenceExecutor.setOnSuccessListener(FirstRequest.class, new OnSuccessListener { 
    public void onSuccess() { 
    sequenceExecutor.setRequest(new SecondRequest()); 
    } 
}; 

sequenceExecutor.setOnFaulListener(FirstRequest.class, new OnFailListener { 
    public void onFail() { 
    sequenceExecutor.setRequest(new OnFirstFailRequest()); 
    } 
}; 

sequenceExecutor.setOnSuccessListener(SecondRequest.class, new OnSuccessListener { 
    public void onSuccess() { 
    notifyDone(); 
    return; 
    } 
}; 

sequenceExecutor.setDefaultOnFailListener(new OnFailListener { 
    public void onFail(Exception e) { 
    notifyDone(); 
    log(e); 
    return; 
    } 
}; 
sequenceExecutor.execute() //starts execution 
Powiązane problemy