Beim Ausführen meines Android-Projekts für RssReader ist ein Fehler aufgetreten.
Code:
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
Und es zeigt den folgenden Fehler:
android.os.NetworkOnMainThreadException
Wie kann ich dieses Problem beheben?
java
android
android-networking
networkonmainthread
Genieße George
quelle
quelle
Antworten:
Diese Ausnahme wird ausgelöst, wenn eine Anwendung versucht, einen Netzwerkvorgang für ihren Hauptthread auszuführen. Führen Sie Ihren Code aus in
AsyncTask
:So führen Sie die Aufgabe aus:
In der
MainActivity.java
Datei können Sie diese Zeile innerhalb Ihreroncreate()
Methode hinzufügenVergessen Sie nicht, dies zur
AndroidManifest.xml
Datei hinzuzufügen :quelle
AsyncTask
und kümmert sich um eine Konfigurationsänderung.Sie sollten Netzwerkvorgänge fast immer in einem Thread oder als asynchrone Aufgabe ausführen.
Es ist jedoch möglich, diese Einschränkung aufzuheben, und Sie überschreiben das Standardverhalten, wenn Sie bereit sind, die Konsequenzen zu akzeptieren.
Hinzufügen:
In deiner Klasse,
und
Fügen Sie diese Berechtigung in der Datei android manifest.xml hinzu:
Konsequenzen:
Ihre App reagiert (in Bereichen mit fleckiger Internetverbindung) nicht mehr und blockiert, der Benutzer nimmt Langsamkeit wahr und muss einen Force-Kill ausführen. Sie riskieren, dass der Aktivitätsmanager Ihre App beendet und dem Benutzer mitteilt, dass die App gestoppt wurde.
Android hat einige gute Tipps für gute Programmierpraktiken, um die Reaktionsfähigkeit zu verbessern : http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
quelle
doInBackground
Deklaration, 2 schließende Klammern und Aufruf vonexecute()
). Auf der anderen Seite führt bereits ein einzelner Abruf von einer Site, wie Sie bereits erwähnt haben, zu einer erheblichen Verzögerung der Reaktionsfähigkeit der Benutzeroberfläche. Sei nicht faul.Ich habe dieses Problem mit einem neuen gelöst
Thread
.quelle
Die akzeptierte Antwort hat einige wesentliche Nachteile. Es ist nicht ratsam, AsyncTask für das Netzwerk zu verwenden, es sei denn, Sie wissen wirklich , was Sie tun. Einige der Nachteile sind:
executeOnExecutor
Methode und geben einen alternativen Executor an). Code, der bei serieller Ausführung auf ICS einwandfrei funktioniert, kann bei gleichzeitiger Ausführung auf Gingerbread beschädigt werden, z. B. wenn Sie versehentliche Abhängigkeiten in der Reihenfolge der Ausführung haben.Wenn Sie Kurzzeitspeicherlecks vermeiden, klar definierte Ausführungseigenschaften auf allen Plattformen haben und eine Basis für eine wirklich robuste Netzwerkverarbeitung haben möchten, sollten Sie Folgendes berücksichtigen:
Service
oderIntentService
stattdessen, möglicherweise mit einemPendingIntent
, um das Ergebnis über dieonActivityResult
Methode der Aktivität zurückzugeben .IntentService-Ansatz
Nachteile:
AsyncTask
, wenn auch nicht so viel, wie Sie vielleicht denkenIntentService
durch eine gleichwertigeService
Implementierung ersetzen , möglicherweise wie diese .Vorteile:
onActivityResult
Methode erhaltenAsyncTask
in einem tun.Activity
Wenn der Benutzerkontext jedoch aus der App wechselt, um einen Anruf entgegenzunehmen, beendet das System die App möglicherweise , bevor der Upload abgeschlossen ist. Es ist weniger wahrscheinlich , eine Anwendung mit einem aktiven zu beendenService
.IntentService
(wie die oben verlinkte) verwenden, können Sie den Grad der Parallelität über die steuernExecutor
.Implementierungszusammenfassung
Sie können
IntentService
ganz einfach einen Download für einen einzelnen Hintergrund-Thread implementieren .Schritt 1: Erstellen Sie eine
IntentService
, um den Download durchzuführen. Sie können angeben, was überIntent
Extras heruntergeladen werden soll , und es übergebenPendingIntent
, um das Ergebnis an Folgendes zurückzugebenActivity
:Schritt 2: Registrieren Sie den Dienst im Manifest:
Schritt 3: Rufen Sie den Dienst über die Aktivität auf und übergeben Sie ein PendingResult-Objekt, mit dem der Dienst das Ergebnis zurückgibt:
Schritt 4: Behandeln Sie das Ergebnis in onActivityResult:
Ein Github-Projekt mit einem vollständig funktionierenden Android-Studio / Gradle-Projekt finden Sie hier .
quelle
IllustrativeRSS
? Was ist, wenn Sie nicht mit RSS arbeiten?AsyncTask
. Der Fehler sollte verhindern, dass Entwickler die Benutzeroberfläche verzögern, und sie nicht unbedingt dazu verleiten, die Sicherheit mit einer Reihe von Absichten / Diensten zu gefährden.Sie können keine Netzwerk- E / A für den UI-Thread von Honeycomb ausführen . Technisch ist dies bei früheren Android-Versionen möglich, aber es ist eine wirklich schlechte Idee, da Ihre App dadurch nicht mehr reagiert und das Betriebssystem Ihre App wegen schlechten Verhaltens töten kann. Sie müssen einen Hintergrundprozess ausführen oder AsyncTask verwenden, um Ihre Netzwerktransaktion in einem Hintergrundthread auszuführen.
Auf der Android-Entwicklerseite gibt es einen Artikel über schmerzloses Threading, der eine gute Einführung in dieses Thema darstellt und Ihnen eine viel bessere Antworttiefe bietet, als hier realistisch angegeben werden kann.
quelle
Verwenden Sie Service oder AsyncTask
Siehe auch Stapelüberlauffrage:
android.os.NetworkOnMainThreadException Senden einer E-Mail von Android
quelle
Führen Sie die Netzwerkaktionen in einem anderen Thread aus
Und fügen Sie dies zu AndroidManifest.xml hinzu
quelle
Sie deaktivieren den strengen Modus mit folgendem Code:
Dies wird nicht empfohlen : Verwenden Sie die
AsyncTask
Schnittstelle.Vollständiger Code für beide Methoden
quelle
Netzwerkbasierte Vorgänge können nicht auf dem Hauptthread ausgeführt werden. Sie müssen alle netzwerkbasierten Aufgaben in einem untergeordneten Thread ausführen oder AsyncTask implementieren.
So führen Sie eine Aufgabe in einem untergeordneten Thread aus:
quelle
Geben Sie Ihren Code ein:
Oder:
quelle
Dies geschieht in Android 3.0 und höher. Ab Android 3.0 haben sie die Ausführung von Netzwerkoperationen (Funktionen, die auf das Internet zugreifen) im Hauptthread / UI-Thread eingeschränkt (was sich aus Ihren On-Create- und On-Resume-Methoden in der Aktivität ergibt).
Dies soll die Verwendung separater Threads für den Netzwerkbetrieb fördern. Weitere Informationen zum richtigen Ausführen von Netzwerkaktivitäten finden Sie unter AsyncTask .
quelle
Die Verwendung von Android-Anmerkungen ist eine Option. Sie können damit einfach eine beliebige Methode in einem Hintergrundthread ausführen:
Beachten Sie, dass es zwar Vorteile in Bezug auf Einfachheit und Lesbarkeit bietet, jedoch seine Nachteile hat.
quelle
Der Fehler ist auf die Ausführung lang laufender Vorgänge im Hauptthread zurückzuführen. Sie können das Problem mithilfe von AsynTask oder Thread problemlos beheben . Sie können diese Bibliothek AsyncHTTPClient zur besseren Handhabung auschecken .
quelle
Sie sollten keine zeitaufwändigen Aufgaben im Hauptthread (UI-Thread) ausführen, wie z. B. Netzwerkoperationen, Datei-E / A- oder SQLite-Datenbankoperationen. Für diese Art von Operation sollten Sie einen Arbeitsthread erstellen. Das Problem besteht jedoch darin, dass Sie keine UI-bezogene Operation direkt von Ihrem Arbeitsthread aus ausführen können. Dafür müssen Sie die verwenden
Handler
und übergebenMessage
.Zur Vereinfachung der all diese Dinge, bietet Android verschiedene Art und Weise, wie
AsyncTask
,AsyncTaskLoader
,CursorLoader
oderIntentService
. Sie können diese also entsprechend Ihren Anforderungen verwenden.quelle
Die Top- Antwort von spektom funktioniert perfekt.
Wenn Sie die
AsyncTask
Inline schreiben und nicht als Klasse erweitern, und obendrein eine Antwort aus der Klasse erhalten müssenAsyncTask
, können Sie die folgendeget()
Methode verwenden.(Aus seinem Beispiel.)
quelle
get()
ist eine schlechte Idee ... es macht AsyncTask wieder "synchronisieren"Dies gilt nur für Anwendungen, die auf das Honeycomb SDK oder höher abzielen . Anwendungen, die auf frühere SDK-Versionen abzielen, dürfen Netzwerke in ihren Hauptereignisschleifenthreads ausführen.
Der Fehler ist die SDK-Warnung!
quelle
Für mich war es das:
Das Gerät, auf dem ich meine App getestet habe, war 4.1.2, SDK Version 16!
Stellen Sie sicher, dass die Zielversion mit Ihrer Android-Zielbibliothek übereinstimmt. Wenn Sie sich nicht sicher sind, was Ihre Zielbibliothek ist, klicken Sie mit der rechten Maustaste auf Ihr Projekt -> Erstellungspfad -> Android . Es sollte das angekreuzte sein.
Schließen Sie, wie bereits erwähnt, die richtigen Berechtigungen für den Zugriff auf das Internet ein:
quelle
NetworkOnMainThreadException
Ist der Wächter, der Ihnen sagt: Schießen Sie nicht auf Ihren eigenen Fuß ... Ihre Lösung lautet: Gehen wir zurück in die Vergangenheit, als es keinen Wächter gab - jetzt kann ich auf meinen schießen Fuß freiVerwenden Sie dies in Ihrer Aktivität
quelle
Nur um etwas explizit zu formulieren:
Der Haupt-Thread ist im Grunde der UI-Thread.
Wenn Sie also sagen, dass Sie keine Netzwerkvorgänge im Hauptthread ausführen können, können Sie keine Netzwerkvorgänge im UI-Thread ausführen. Dies bedeutet, dass Sie auch keine Netzwerkvorgänge in einem
*runOnUiThread(new Runnable() { ... }*
Block in einem anderen Thread ausführen können.(Ich hatte gerade einen langen Moment am Kopf kratzen, um herauszufinden, warum ich diesen Fehler irgendwo anders als in meinem Haupt-Thread bekam. Deshalb; dieser Thread hat geholfen; und hoffentlich hilft dieser Kommentar jemand anderem.)
quelle
Diese Ausnahme tritt aufgrund jeder schwere Aufgabe auf dem Haupt - Thread ausgeführt , wenn diese Aufgabe ausführt nimmt zu viel Zeit .
Um dies zu vermeiden, können wir mit Threads oder Executoren damit umgehen
quelle
Es gibt bereits viele großartige Antworten auf diese Frage, aber seit diese Antworten veröffentlicht wurden, sind viele großartige Bibliotheken herausgekommen. Dies ist als eine Art Newbie-Guide gedacht.
Ich werde mehrere Anwendungsfälle für die Durchführung von Netzwerkoperationen und jeweils eine oder zwei Lösungen behandeln.
ReST über HTTP
Typischerweise kann Json XML oder etwas anderes sein
Voller API-Zugriff
Angenommen, Sie schreiben eine App, mit der Benutzer Aktienkurse, Zinssätze und Wechselkurse verfolgen können. Sie finden eine Json-API, die ungefähr so aussieht:
Nachrüstung vom Platz
Dies ist eine ausgezeichnete Wahl für eine API mit mehreren Endpunkten und ermöglicht es Ihnen, die ReST-Endpunkte zu deklarieren, anstatt sie wie bei anderen Bibliotheken wie ion oder Volley einzeln codieren zu müssen. (Website: http://square.github.io/retrofit/ )
Wie verwenden Sie es mit der Finanz-API?
build.gradle
Fügen Sie diese Zeilen zu Ihrer Modulebene hinzu buid.gradle:
FinancesApi.java
FinancesApiBuilder
FinancesFragment-Snippet
Wenn für Ihre API ein API-Schlüssel oder ein anderer Header wie ein Benutzertoken usw. gesendet werden muss, macht Retrofit dies einfach (Einzelheiten finden Sie in dieser fantastischen Antwort: https://stackoverflow.com/a/42899766/1024412 ).
Einmaliger ReST-API-Zugriff
Angenommen, Sie erstellen eine "Stimmungswetter" -App, die den GPS-Standort des Benutzers abruft, die aktuelle Temperatur in diesem Bereich überprüft und ihm die Stimmung mitteilt. Diese Art von App muss keine API-Endpunkte deklarieren. Es muss nur auf einen API-Endpunkt zugreifen können.
Ion
Dies ist eine großartige Bibliothek für diese Art des Zugriffs.
Bitte lesen Sie die großartige Antwort von msysmilu ( https://stackoverflow.com/a/28559884/1024412 ).
Laden Sie Bilder über HTTP
Volley
Volley kann auch für ReST-APIs verwendet werden. Aufgrund der komplizierteren Einrichtung bevorzuge ich jedoch die Nachrüstung von Square wie oben ( http://square.github.io/retrofit/ ).
Angenommen, Sie erstellen eine Social-Networking-App und möchten Profilbilder von Freunden laden.
build.gradle
Fügen Sie diese Zeile Ihrer Modulebene hinzu buid.gradle:
ImageFetch.java
Volley erfordert mehr Setup als Nachrüstung. Sie müssen eine Klasse wie diese erstellen, um eine RequestQueue, einen ImageLoader und einen ImageCache einzurichten, aber es ist nicht schlecht:
user_view_dialog.xml
Fügen Sie Ihrer XML-Layoutdatei Folgendes hinzu, um ein Bild hinzuzufügen:
UserViewDialog.java
Fügen Sie der onCreate-Methode (Fragment, Activity) oder dem Konstruktor (Dialog) den folgenden Code hinzu:
Picasso
Eine weitere ausgezeichnete Bibliothek von Square. Auf der Website finden Sie einige gute Beispiele: http://square.github.io/picasso/
quelle
In einfachen Worten,
NETZWERK NICHT IM UI-GEWINDE ARBEITEN
Wenn Sie beispielsweise eine HTTP-Anforderung ausführen, handelt es sich um eine Netzwerkaktion.
Lösung:
Weg:
Legen Sie alle Ihre Werke hinein
run()
Methode des neuen ThreadsdoInBackground()
Methode der AsyncTask-Klasse.Aber:
Wenn Sie eine Netzwerkantwort erhalten und diese in Ihrer Ansicht anzeigen möchten (z. B. Antwortnachricht in TextView anzeigen), müssen Sie zum UI- Thread zurückkehren.
Wenn Sie es nicht tun, werden Sie bekommen
ViewRootImpl$CalledFromWrongThreadException
.Wie man?
onPostExecute()
MethoderunOnUiThread()
Methode auf und aktualisieren Sie die Ansicht innerhalb derrun()
Methode.quelle
Sie sind in der Lage , einen Teil des Codes in einen anderen Thread bewegen die abzuladen
main thread
und vermeiden bekommen ANR , NetworkOnMainThreadException , Illegal (zB hat keinen Zugriff auf Datenbank auf dem Haupt - Thread , da es möglicherweise die Benutzeroberfläche für eine längere Zeit sperren kann).Es gibt einige Ansätze, die Sie je nach Situation wählen sollten
Java Thread oder Android HandlerThread
AsyncTask
Thread-Pool-Implementierung ThreadPoolExecutor , ScheduledThreadPoolExecutor ...
FutureTask
AsyncTaskLoaders
IntentService
JobScheduler
RxJava
Coroutinen (Kotlin)
Lesen Sie hier , hier , hier , hier mehr
quelle
Obwohl es oben einen riesigen Lösungspool gibt, erwähnte niemand
com.koushikdutta.ion
: https://github.com/koush/ionEs ist auch asynchron und sehr einfach zu bedienen:
quelle
Neue
Thread
und AsyncTask- Lösungen wurden bereits erläutert.AsyncTask
sollte idealerweise für kurze Operationen verwendet werden. NormalThread
ist für Android nicht vorzuziehen.Schauen Sie sich eine alternative Lösung mit HandlerThread und Handler an
HandlerThread
Handler:
Lösung:
Erstellen
HandlerThread
Rufen Sie
start()
anHandlerThread
Erstellen Sie,
Handler
indem sieLooper
ausHanlerThread
Betten Sie Ihren Code für den Netzwerkbetrieb in das
Runnable
Objekt einRunnable
Aufgabe senden anHandler
Beispielcode-Snippet, welche Adresse
NetworkOnMainThreadException
Vorteile dieses Ansatzes:
Thread/AsyncTask
für jeden Netzwerkbetrieb ist teuer. DasThread/AsyncTask
wird zerstört und für den nächsten Netzwerkbetrieb neu erstellt. MitHandler
undHandlerThread
Ansatz können Sie jedoch viele Netzwerkvorgänge (als ausführbare Aufgaben)HandlerThread
mithilfe von an einzelne sendenHandler
.quelle
RxAndroid
ist eine weitere bessere Alternative zu diesem Problem und erspart uns den Aufwand, Threads zu erstellen und dann Ergebnisse auf dem Android-UI-Thread zu veröffentlichen. Wir müssen nur Threads angeben, auf denen Aufgaben ausgeführt werden müssen, und alles wird intern erledigt.Durch Angabe
(Schedulers.io())
wird RxAndroidgetFavoriteMusicShows()
auf einem anderen Thread ausgeführt.Mit verwenden
AndroidSchedulers.mainThread()
möchten wir diese Observable im UI-Thread beobachten, dh wir möchten, dass unseronNext()
Rückruf im UI-Thread aufgerufen wirdquelle
Der Hauptthread ist der UI-Thread, und Sie können im Hauptthread keine Operation ausführen, die die Benutzerinteraktion blockieren könnte. Sie können dies auf zwei Arten lösen:
Erzwingen Sie die Ausführung der Aufgabe im Hauptthread wie folgt
Oder erstellen Sie einen einfachen Handler und aktualisieren Sie den Hauptthread, wenn Sie möchten.
Und um den Thread zu stoppen, verwenden Sie:
Weitere Informationen finden Sie hier: Schmerzloses Einfädeln
quelle
Das funktioniert. Ich habe gerade Dr.Luijis Antwort etwas einfacher gemacht.
quelle
Unter Android können Netzwerkvorgänge nicht im Hauptthread ausgeführt werden. Sie können Thread, AsyncTask (kurz laufende Aufgaben) und Service (lang laufende Aufgaben) verwenden, um Netzwerkoperationen auszuführen.
quelle
Der Zugriff auf Netzwerkressourcen über den Hauptthread (UI) verursacht diese Ausnahme. Verwenden Sie einen separaten Thread oder AsyncTask für den Zugriff auf eine Netzwerkressource, um dieses Problem zu vermeiden.
quelle