Wie kann ich „android.os.NetworkOnMainThreadException“ beheben?

Lesezeit: 8 Minuten

1646790791 232 Wie kann ich „androidosNetworkOnMainThreadException beheben
genieße george

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?

  • Lesen Sie diesen Blogbeitrag auf der NetworkOnMainThreadException für weitere Informationen. Es erklärt, warum dies bei Android 3.0 und höher auftritt.

    – Adrian Mönch

    7. August 2012 um 12:38 Uhr

  • Um auf dem richtigen Weg zu sein, lesen Sie zuerst etwas über die Netzwerkanfragen in Android, dann würde ich empfehlen, “Volley” zu studieren.

    – Anuj Sharma

    23. Januar 2014 um 6:39 Uhr

  • Es gibt viele alternative Bibliotheken, die dieses Problem lösen. Viele sind aufgelistet unten auf dieser Seite. Wenn du mehr hast, nehmen wir sie 🙂

    – Snikola

    11. Februar 2014 um 22:55 Uhr

  • Sie müssen Internetaktivitäten in einem Thread ausführen, der vom Hauptthread (UI) getrennt ist

    – Naveed Ahmad

    30. Oktober 2014 um 20:44 Uhr

  • “Aufgrund eines Fehlers in früheren Versionen von Android hat das System das Schreiben in einen TCP-Socket im Haupt-Thread nicht als Verstoß gegen den strikten Modus gekennzeichnet. Android 7.0 behebt diesen Fehler. Apps, die dieses Verhalten aufweisen, werfen jetzt ein android.os. NetworkOnMainThreadException.” – Also einige von uns haben das bis vor kurzem nicht getroffen! developer.android.com/about/versions/nougat/…

    – Jay

    19. November 2017 um 22:51 Uhr

1646790792 287 Wie kann ich „androidosNetworkOnMainThreadException beheben
Benutzer1169115

Sie sollten Netzwerkvorgänge fast immer in einem Thread oder als asynchrone Aufgabe ausführen.

Aber es ist Es ist möglich, diese Einschränkung aufzuheben, und Sie setzen das Standardverhalten außer Kraft, wenn Sie bereit sind, die Konsequenzen zu akzeptieren.

Addieren:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy);

In deiner Klasse,

und

Addieren diese Berechtigung im Android manifest.xml Datei:

<uses-permission android:name="android.permission.INTERNET"/>

Konsequenzen:

Ihre App wird (in Bereichen mit lückenhafter Internetverbindung) nicht mehr reagieren und abstürzen, der Benutzer nimmt die Langsamkeit wahr und muss einen Force-Kill durchführen, und Sie riskieren, dass der Aktivitätsmanager Ihre App beendet und dem Benutzer mitteilt, dass die App beendet wurde.

Android hat einige gute Tipps zu guten Programmierpraktiken für ein reaktionsschnelles Design:
NetworkOnMainThreadException | Android-Entwickler

  • Wow, danke für die Erklärung, die ich jetzt verstehe. Ich sah eine App und sie hatte diese ThreadPolicy in ihren Java-Klassen implementiert. Ich war etwas verwirrt, was sie tat. Als das Netzwerk schwach war, sah ich die Konsequenz, von der Sie sprachen.

    – MoseK

    3. Juni 2021 um 9:30 Uhr

  • Wie würden Sie Parameter dazu übergeben?

    – Haisi

    3. Juni 2021 um 7:42 Uhr

  • Wenn Sie nach der Anfrage auf die Benutzeroberfläche zugreifen müssen, müssen Sie am Ende zum Hauptthread zurückkehren, wie hier erklärt.

    – Donald Duck

    9. August 2021 um 10:43 Uhr

1646790793 43 Wie kann ich „androidosNetworkOnMainThreadException beheben
Stevie

Die akzeptierte Antwort hat einige erhebliche Nachteile. Es ist nicht ratsam, AsyncTask für das Netzwerk zu verwenden, es sei denn, Sie Ja wirklich weiß was du tust. Einige der Nachteile sind:

  • AsyncTasks, die als nicht statische innere Klassen erstellt wurden, haben einen impliziten Verweis auf das einschließende Activity-Objekt, seinen Kontext und die gesamte View-Hierarchie, die von dieser Aktivität erstellt wurde. Dieser Verweis verhindert, dass die Aktivität von der Garbage Collection erfasst wird, bis die Hintergrundarbeit von AsyncTask abgeschlossen ist. Wenn die Verbindung des Benutzers langsam und/oder der Download groß ist, können diese Kurzzeitgedächtnislecks zu einem Problem werden – zum Beispiel, wenn sich die Orientierung mehrmals ändert (und Sie die auszuführenden Aufgaben nicht abbrechen) oder der Benutzer navigiert von der Aktivität weg.
  • AsyncTask hat je nach Plattform, auf der es ausgeführt wird, unterschiedliche Ausführungsmerkmale: vor API-Ebene 4 werden AsyncTasks seriell auf einem einzelnen Hintergrund-Thread ausgeführt; von API-Level 4 bis API-Level 10 werden AsyncTasks auf einem Pool von bis zu 128 Threads ausgeführt; Ab API-Level 11 wird AsyncTask seriell auf einem einzelnen Hintergrundthread ausgeführt (es sei denn, Sie verwenden die überladene executeOnExecutor Methode und Bereitstellung eines alternativen Ausführenden). Code, der gut funktioniert, wenn er seriell auf ICS ausgeführt wird, kann bei gleichzeitiger Ausführung auf Gingerbread brechen, z. B. wenn Sie unbeabsichtigte Abhängigkeiten in der Ausführungsreihenfolge haben.

Wenn Sie kurzfristige Speicherlecks vermeiden möchten, über gut definierte Ausführungsmerkmale auf allen Plattformen verfügen und eine Basis haben möchten, um eine wirklich robuste Netzwerkverarbeitung aufzubauen, sollten Sie Folgendes in Betracht ziehen:

  1. Verwenden Sie eine Bibliothek, die dies gut für Sie erledigt – in dieser Frage finden Sie einen schönen Vergleich von Netzwerkbibliotheken, oder
  2. Verwendung einer Service oder IntentService stattdessen vielleicht mit a PendingIntent um das Ergebnis über die Aktivität zurückzugeben onActivityResult Methode.

IntentService-Ansatz

Nachteile:

  • Mehr Code und Komplexität als AsyncTaskwenn auch nicht so viel, wie Sie vielleicht denken
  • Wird Anfragen in die Warteschlange stellen und sie auf a ausführen Einzel Hintergrundthread. Sie können dies leicht durch Ersetzen steuern IntentService mit einem Äquivalent Service Umsetzung, vielleicht wie Dieses hier.
  • Ähm, mir fallen gerade keine anderen ein

Vorteile:

  • Vermeidet das Problem des Kurzzeitgedächtnisses
  • Wenn Ihre Aktivität neu gestartet wird, während der Netzwerkbetrieb läuft, kann sie das Ergebnis des Downloads dennoch über seine empfangen onActivityResult Methode
  • Eine bessere Plattform als AsyncTask, um robusten Netzwerkcode zu erstellen und wiederzuverwenden. Beispiel: Wenn Sie einen wichtigen Upload durchführen müssen, können Sie dies von tun AsyncTask in einem (n Activityaber wenn der Benutzer den Kontext der App verlässt, um einen Anruf entgegenzunehmen, wird das system dürfen Beenden Sie die App, bevor der Upload abgeschlossen ist. es ist weniger wahrscheinlich um eine Anwendung mit einem aktiven zu beenden Service.
  • Wenn Sie Ihre eigene Concurrent-Version von IntentService (wie die, die ich oben verlinkt habe) können Sie den Grad der Parallelität über die steuern Executor.

Zusammenfassung der Umsetzung

Sie können eine implementieren IntentService um ganz einfach Downloads auf einem einzelnen Hintergrund-Thread durchzuführen.

Schritt 1: Erstellen Sie eine IntentService um den Download durchzuführen. Sie können ihm mitteilen, was heruntergeladen werden soll Intent Extras, und übergeben Sie es a PendingIntent verwenden, um das Ergebnis an die zurückzugeben Activity:

import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class DownloadIntentService extends IntentService {

    private static final String TAG = DownloadIntentService.class.getSimpleName();

    public static final String PENDING_RESULT_EXTRA = "pending_result";
    public static final String URL_EXTRA = "url";
    public static final String RSS_RESULT_EXTRA = "url";

    public static final int RESULT_CODE = 0;
    public static final int INVALID_URL_CODE = 1;
    public static final int ERROR_CODE = 2;

    private IllustrativeRSSParser parser;

    public DownloadIntentService() {
        super(TAG);

        // make one and reuse, in the case where more than one intent is queued
        parser = new IllustrativeRSSParser();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
        InputStream in = null;
        try {
            try {
                URL url = new URL(intent.getStringExtra(URL_EXTRA));
                IllustrativeRSS rss = parser.parse(in = url.openStream());

                Intent result = new Intent();
                result.putExtra(RSS_RESULT_EXTRA, rss);

                reply.send(this, RESULT_CODE, result);
            } catch (MalformedURLException exc) {
                reply.send(INVALID_URL_CODE);
            } catch (Exception exc) {
                // could do better by treating the different sax/xml exceptions individually
                reply.send(ERROR_CODE);
            }
        } catch (PendingIntent.CanceledException exc) {
            Log.i(TAG, "reply cancelled", exc);
        }
    }
}

Schritt 2: Registrieren Sie den Dienst im Manifest:

<service
        android:name=".DownloadIntentService"
        android:exported="false"/>

Schritt 3: Rufen Sie den Dienst aus der Aktivität auf und übergeben Sie ein PendingResult-Objekt, das der Dienst verwendet, um das Ergebnis zurückzugeben:

PendingIntent pendingResult = createPendingResult(
    RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);

Schritt 4: Behandeln Sie das Ergebnis in onActivityResult:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
        switch (resultCode) {
            case DownloadIntentService.INVALID_URL_CODE:
                handleInvalidURL();
                break;
            case DownloadIntentService.ERROR_CODE:
                handleError(data);
                break;
            case DownloadIntentService.RESULT_CODE:
                handleRSS(data);
                break;
        }
        handleRSS(data);
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Ein GitHub-Projekt, das ein vollständig funktionierendes Android Studio enthält/Gradl Projekt liegt vor Hier.

1646790794 316 Wie kann ich „androidosNetworkOnMainThreadException beheben
Peter Mortensen

Sie können kein Netzwerk ausführen E/A auf dem UI-Thread auf Bienenwabe. Technisch gesehen ist es ist auf früheren Versionen von Android möglich, aber es ist eine wirklich schlechte Idee, da es dazu führt, dass Ihre App nicht mehr reagiert, und dazu führen kann, dass das Betriebssystem Ihre App wegen schlechten Benehmens beendet. Sie müssen einen Hintergrundprozess ausführen oder AsyncTask verwenden, um Ihre Netzwerktransaktion in einem Hintergrundthread auszuführen.

Es gibt einen Artikel darüber Schmerzloses Einfädeln auf der Android-Entwicklerseite, die eine gute Einführung in dieses Thema darstellt und Ihnen eine viel bessere Antworttiefe bietet, als dies hier realistisch möglich ist.

1646790794 316 Wie kann ich „androidosNetworkOnMainThreadException beheben
Peter Mortensen

Es gibt zwei Lösungen für dieses Problem.

  1. Verwenden Sie im Haupt-UI-Thread keinen Netzwerkaufruf. Verwenden Sie dafür eine asynchrone Aufgabe.

  2. Schreiben Sie danach den folgenden Code in Ihre MainActivity-Datei setContentView (R.layout.activity_main);:

    if (android.os.Build.VERSION.SDK_INT > 9) {StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy (Richtlinie); }

Und die folgende import-Anweisung in Ihre Java-Datei.

import android.os.StrictMode;

  • Das Befolgen Ihrer zweiten Lösung ist eine schlechte Praxis. Async ist der Weg, es zu tun korrekt. Sie verstecken Ihr Problem gerne, wenn Sie die Richtlinie ändern!

    – Richi González

    28. Mai 2013 um 7:47 Uhr

979550cookie-checkWie kann ich „android.os.NetworkOnMainThreadException“ beheben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy