Stellen Sie sich vor, ich bin in einem Dienst, der bereits einen Hintergrund-Thread hat. Kann ich eine Anfrage mit Volley in demselben Thread stellen, damit Rückrufe synchron erfolgen?
Dafür gibt es zwei Gründe: - Erstens brauche ich keinen weiteren Thread und es wäre eine Verschwendung, ihn zu erstellen. - Zweitens, wenn ich mich in einem ServiceIntent befinde, wird die Ausführung des Threads vor dem Rückruf beendet, und daher werde ich keine Antwort von Volley erhalten. Ich weiß, dass ich meinen eigenen Dienst erstellen kann, der einen Thread mit einem Runloop hat, den ich steuern kann, aber es wäre wünschenswert, diese Funktionalität in Volley zu haben.
Danke dir!
java
android
android-volley
LocoMike
quelle
quelle
Antworten:
Es sieht so aus, als wäre es mit Volleys
RequestFuture
Klasse möglich. Um beispielsweise eine synchrone JSON-HTTP-GET-Anforderung zu erstellen, haben Sie folgende Möglichkeiten:quelle
JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorlistener)
Konstruktor.RequestFuture<JSONObject>
implementiert sowohl dieListener<JSONObject>
als auch dieErrorListener
Schnittstellen und kann daher als die letzten beiden Parameter verwendet werden.future.get()
wird die App blockiert oder es tritt mit Sicherheit eine Zeitüberschreitung auf, wenn dies festgelegt ist.Hinweis: Die Antwort von @Matthews ist korrekt, ABER wenn Sie sich in einem anderen Thread befinden und einen Volley-Anruf tätigen, wenn Sie kein Internet haben, wird Ihr Fehlerrückruf im Haupt-Thread aufgerufen, aber der Thread, in dem Sie sich befinden, wird für immer blockiert. (Wenn es sich bei diesem Thread um einen IntentService handelt, können Sie niemals eine weitere Nachricht an ihn senden, und Ihr Dienst ist im Grunde genommen tot.)
Verwenden Sie die Version
get()
davon hat eine Zeitüberschreitungfuture.get(30, TimeUnit.SECONDS)
und fangen Sie den Fehler ab, um Ihren Thread zu beenden.Passend zu @Mathews Antwort:
Unten habe ich es in eine Methode eingewickelt und eine andere Anfrage verwendet:
quelle
IntentService
ist ein Thread-Pool-Executor eines einzelnen Threads, daher wird IntentService für immer blockiert, da es sich in einer Schleife befindetEs wird wahrscheinlich empfohlen, die Futures zu verwenden, aber wenn Sie aus irgendeinem Grund nicht möchten, sollten Sie eine verwenden, anstatt Ihre eigene synchronisierte Blockierungssache zu kochen
java.util.concurrent.CountDownLatch
. Das würde also so funktionieren ..Da die Leute tatsächlich zu versuchen schienen, dies zu tun, und auf einige Probleme stießen, beschloss ich, tatsächlich ein "reales" Arbeitsprobe davon zur Verfügung zu stellen. Hier ist es https://github.com/timolehto/SynchronousVolleySample
Obwohl die Lösung funktioniert, gibt es einige Einschränkungen. Am wichtigsten ist, dass Sie es nicht im Haupt-UI-Thread aufrufen können. Volley führt die Anforderungen zwar im Hintergrund aus, aber standardmäßig verwendet Volley den Hauptteil
Looper
der Anwendung, um die Antworten zu versenden. Dies führt zu einem Deadlock, da der Haupt-UI-Thread auf die Antwort wartet, der jedoch auf den AbschlussLooper
wartetonCreate
, bevor die Lieferung verarbeitet wird. Wenn Sie dies wirklich wirklich tun möchten, können Sie anstelle der statischen Hilfsmethoden Ihre eigeneRequestQueue
Instanz instanziieren, indem Sie Ihre eigeneExecutorDelivery
an eineHandler
verwenden,Looper
die an einen anderen Thread als den Haupt-UI-Thread gebunden ist.quelle
Als ergänzende Beobachtung zu den Antworten von @Blundells und @Mathews bin ich mir nicht sicher, ob ein Anruf von Volley an etwas anderes als den Haupt-Thread gesendet wird.
Die Quelle
Bei einem Blick auf die
RequestQueue
Implementierung scheintRequestQueue
es, dass a verwendet wirdNetworkDispatcher
, um die Anforderung auszuführen, und aResponseDelivery
, um das Ergebnis zu liefern (dasResponseDelivery
wird in das injiziertNetworkDispatcher
). DasResponseDelivery
wird wiederum mit einemHandler
Spawn aus dem Hauptthread erstellt (irgendwo um Zeile 112 in derRequestQueue
Implementierung).Irgendwo in Zeile 135 der
NetworkDispatcher
Implementierung scheinen auch erfolgreiche Ergebnisse durchResponseDelivery
Fehler geliefert zu werden. Nochmal; aResponseDelivery
basierend auf aHandler
Spawn aus dem Haupt-Thread.Begründung
Für den Anwendungsfall, in dem eine Anfrage von einem gestellt werden soll
IntentService
soll, kann davon ausgegangen werden, dass der Thread des Dienstes blockiert werden sollte, bis wir eine Antwort von Volley erhalten (um einen lebendigen Laufzeitbereich zu gewährleisten, in dem das Ergebnis verarbeitet werden kann).Lösungsvorschläge
Ein Ansatz wäre , um die Standard Weise außer Kraft setzen ein
RequestQueue
erstellt wird , in der ein alternativer Konstruktor stattdessen verwendet wird, die Injektion ein ,ResponseDelivery
die Spawns aus dem aktuellen Thread eher als der Haupt - Thread. Ich habe die Auswirkungen davon jedoch nicht untersucht.quelle
finish()
Methode in derRequest
Klasse und dieRequestQueue
Klasse paketprivat sind. Abgesehen von der Verwendung eines Reflection-Hacks bin ich mir nicht sicher, ob es einen Weg gibt, dies zu umgehen. Am Ende habe ich einen alternativen Looper-Thread eingerichtet (usingLooper.prepareLooper(); Looper.loop()
) und eineExecutorDelivery
InstanzRequestQueue
mit einem Handler für diesen Looper an den Konstruktor übergeben , um zu verhindern, dass etwas auf dem Hauptthread (UI) ausgeführt wird . Sie haben den Overhead eines anderen Loopers, bleiben aber vom Hauptfaden fernIch benutze eine Sperre, um diesen Effekt zu erzielen. Jetzt frage ich mich, ob es richtig ist, wie jemand etwas kommentieren möchte.
quelle
catch (InterruptedException e)
die while-Schleife zu verwenden. Andernfalls kann der Thread nicht warten, wenn er aus irgendeinem Grund unterbrochen wirdIch möchte etwas zu Matthews akzeptierter Antwort hinzufügen. Während
RequestFuture
könnte einen synchronen Aufruf aus dem Thread zu machen scheinen Sie es erstellt hat , ist es nicht. Stattdessen wird der Aufruf in einem Hintergrundthread ausgeführt.Soweit ich weiß, werden nach dem Durchlaufen der Bibliothek Anfragen in der folgenden Methode
RequestQueue
versendetstart()
:Jetzt beide
CacheDispatcher
undNetworkDispatcher
Klassen den Thread. So wird effektiv ein neuer Worker-Thread erzeugt, um die Anforderungswarteschlange aus der Warteschlange zu entfernen, und die Antwort wird an die Erfolgs- und Fehler-Listener zurückgegeben, die intern von implementiert wurdenRequestFuture
.Ihr zweiter Zweck wird zwar erreicht, Ihr erster Zweck jedoch nicht, da immer ein neuer Thread erzeugt wird, unabhängig davon, von welchem Thread Sie ausgeführt werden
RequestFuture
.Zusamenfassend, echte synchrone Anforderung ist mit der Standard-Volley-Bibliothek nicht möglich. Korrigieren Sie mich, wenn ich falsch liege.
quelle
Sie können eine Synchronisierungsanforderung mit Volley ausführen, müssen jedoch die Methode in einem anderen Thread aufrufen. Andernfalls wird Ihre laufende App blockiert. Dies sollte folgendermaßen aussehen:
Danach können Sie die Methode im Thread aufrufen:
quelle