Wie behebe ich 'android.os.NetworkOnMainThreadException'?

2394

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?

Genieße George
quelle
131
Weitere Informationen finden Sie in diesem Blogbeitrag in der NetworkOnMainThreadException. Es wird erklärt, warum dies unter Android 3.0 und höher auftritt.
Adrian Monk
6
Um auf dem richtigen Weg zu sein, lesen Sie zuerst die Netzwerkanforderungen in Android und dann würde ich empfehlen, "Volley" zu studieren.
Anuj Sharma
3
Es gibt viele alternative Bibliotheken, die dieses Problem lösen. Viele sind am Ende dieser Seite aufgeführt . Wenn Sie mehr haben, nehmen wir sie :)
Snicolas
Sie müssen Internetaktivitäten auf einem Thread ausführen, der vom Hauptthread (UI) getrennt ist
Naveed Ahmad
"Aufgrund eines Fehlers in früheren Android-Versionen hat das System das Schreiben in einen TCP-Socket im Hauptthread nicht als Verstoß gegen den strengen Modus gekennzeichnet. Android 7.0 behebt diesen Fehler. Apps, die dieses Verhalten aufweisen, werfen jetzt eine android.os aus. NetworkOnMainThreadException. " - Einige von uns haben das also erst vor kurzem getroffen! developer.android.com/about/versions/nougat/…
Jay

Antworten:

2547

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:

class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {

    private Exception exception;

    protected RSSFeed doInBackground(String... urls) {
        try {
            URL url = new URL(urls[0]);
            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();
        } catch (Exception e) {
            this.exception = e;

            return null;
        } finally {
            is.close();
        }
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

So führen Sie die Aufgabe aus:

In der MainActivity.javaDatei können Sie diese Zeile innerhalb Ihrer oncreate()Methode hinzufügen

new RetrieveFeedTask().execute(urlToRssFeed);

Vergessen Sie nicht, dies zur AndroidManifest.xmlDatei hinzuzufügen :

<uses-permission android:name="android.permission.INTERNET"/>
Michael Spector
quelle
37
Ich denke, es ist erwähnenswert, dass das obige Code-Snippet eine Unterklasse (innere Klasse) sein soll, vorzugsweise privat. Auf diese Weise können Sie nach Abschluss der AsyncTask die Innereien Ihrer Klasse noch manipulieren.
Legasthenikeraboko
4
Eigentlich habe ich die gleiche Sache wie u oben erwähnt , aber m diesen Fehler auftritt java.lang.RuntimeException: Kann nicht Handler Innengewinde erstellen , die nicht Looper.prepare genannt hat ()
Dhruv Tyagi
68
Dies ist genau die falsche Antwort. Ich stoße die ganze Zeit im Code der Leute darauf, und es ist ärgerlich, es die ganze Zeit reparieren zu müssen. AsyncTask sollte nicht für Netzwerkaktivitäten verwendet werden, da es an die Aktivität gebunden ist, jedoch nicht an den Aktivitätslebenszyklus. Wenn Sie das Gerät drehen, während diese Aufgabe ausgeführt wird, wird eine Ausnahme ausgelöst und Ihre App stürzt ab. Verwenden Sie stattdessen einen IntentService, der Daten in der SQLite-Datenbank löscht.
Brill Pappin
5
Achtung, AsyncTask wird häufig für Netzwerkvorgänge pro Aktivität verwendet, wenn dies nicht der Fall sein sollte. Sein Lebenszyklus stimmt nicht mit der Aktivität überein. Zum Abrufen von Daten sollten Sie einen IntentService und die Datenbank hinter der Ansicht verwenden.
Brill Pappin
1
@BrillPappin, FWIW, dieses Android-Entwicklerhandbuch verwendet AsyncTaskund kümmert sich um eine Konfigurationsänderung.
HeyJude
677

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:

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

StrictMode.setThreadPolicy(policy); 

In deiner Klasse,

und

Fügen Sie diese Berechtigung in der Datei android manifest.xml hinzu:    

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

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

user1169115
quelle
456
Das ist eine sehr schlechte Idee. Die Lösung besteht darin, Netzwerk-E / A im Hauptthread zu vermeiden (wie die akzeptierte Antwort zeigt).
MByD
74
Damit verstecken Sie nur Ihr eigentliches Problem.
Alex
28
@TwistedUmbrella Die AsyncTask fügt keine Codeseite hinzu, sondern 6 Zeilen (Klassendeklaration, Überschreibungsanmerkung, doInBackgroundDeklaration, 2 schließende Klammern und Aufruf von execute()). 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.
Zoltán
19
Ich denke, dies ist die perfekte Lösung, wenn Sie nur einen Beispielblock Code ausführen möchten, um zu prüfen, ob etwas funktioniert, bevor Sie die richtige AsyncTask implementieren. Aus diesem Grund habe ich diese Antwort positiv bewertet, obwohl dies, wie alle anderen gesagt haben, nicht in einer Produktions-App erfolgen sollte, sondern nur als schnelle Problemumgehung für einen Entwicklertest.
Hooked82
94
Upvoted. Diese Antwort ist richtig, und für die vielen Programmierer, die weder naiv noch dumm sind, aber einfach einen SYNCHRONEN (dh: dies muss die App blockieren ) Aufruf benötigen , ist dies genau das, was benötigt wird. Ich bin mehr als froh, dass Android standardmäßig die Ausnahme auslöst (IMHO ist es eine sehr "hilfreiche" Sache!) - aber ich bin ebenso glücklich, "Danke, aber - das ist eigentlich das, was ich beabsichtigt habe" zu sagen und zu überschreiben es.
Adam
428

Ich habe dieses Problem mit einem neuen gelöst Thread.

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

thread.start(); 
Dr. Luiji
quelle
7
Anstatt jedes Mal, wenn Sie einen Netzwerkvorgang ausführen möchten, einen neuen Thread zu erstellen, können Sie auch einen einzelnen Thread-Executor-Dienst verwenden.
Alex Lockwood
66
Einfach aber gefährlich. Die anonyme ausführbare Datei hat einen impliziten Verweis auf die einschließende Klasse (z. B. Ihre Aktivität oder Ihr Fragment), wodurch verhindert wird, dass sie bis zum Abschluss des Threads als Müll gesammelt wird. Sie sollten mindestens die Priorität auf Process.BACKGROUND setzen, da dieser Thread sonst mit der gleichen Priorität wie der Haupt- / UI-Thread ausgeführt wird und mit Lebenszyklusmethoden und UI-Frameraten konkurriert (achten Sie auf Warnungen im Protokoll des Choreografen).
Stevie
1
@Stevie wie man die Priorität setzt? Weder runnble noch der executorService haben eine solche Setter-Methode
JK
1
@JK Stellen Sie Ihrem ExecutorService eine benutzerdefinierte ThreadFactory zur Verfügung und rufen Sie Thread.setPriority für den Thread auf, bevor Sie ihn zurückgeben.
Stevie
1
"Es wird davon abgeraten, Threads direkt in Android zu verwenden. Es verursacht mehr Probleme als es löst." Möchten Sie das näher erläutern? Tatsächlich wird AsyncTask genau dafür veraltet ... techyourchance.com/asynctask-deprecated
Fran Marzoa
170

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:

  • Als nicht statische innere Klassen erstellte AsyncTask haben einen impliziten Verweis auf das einschließende Aktivitätsobjekt, seinen Kontext und die gesamte von dieser Aktivität erstellte Ansichtshierarchie. Diese Referenz verhindert, dass die Aktivität mit Müll gesammelt wird, bis die Hintergrundarbeit der AsyncTask abgeschlossen ist. Wenn die Verbindung des Benutzers langsam ist und / oder der Download groß ist, können diese Kurzzeitspeicherlecks zu einem Problem werden - beispielsweise wenn sich die Ausrichtung mehrmals ändert (und Sie die ausgeführten Aufgaben nicht abbrechen) oder der Benutzer navigiert von der Aktivität weg.
  • AsyncTask weist je nach Plattform, auf der es ausgeführt wird, unterschiedliche Ausführungseigenschaften auf: Vor API-Ebene 4 werden AsyncTasks seriell auf einem einzelnen Hintergrundthread ausgeführt. Von API-Ebene 4 bis API-Ebene 10 werden AsyncTasks in einem Pool von bis zu 128 Threads ausgeführt. Ab API-Ebene 11 wird AsyncTask seriell auf einem einzelnen Hintergrundthread ausgeführt (es sei denn, Sie verwenden die überladene executeOnExecutorMethode 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:

  1. Mit Hilfe eine Bibliothek , die eine schöne Aufgabe , dies für Sie tut - es ist ein schöner Vergleich von Libs in der Vernetzung dieser Frage , oder
  2. Verwenden Sie ein Serviceoder IntentServicestattdessen, möglicherweise mit einem PendingIntent, um das Ergebnis über die onActivityResultMethode der Aktivität zurückzugeben .

IntentService-Ansatz

Nachteile:

  • Mehr Code und Komplexität als AsyncTask, wenn auch nicht so viel, wie Sie vielleicht denken
  • Stellt Anforderungen in die Warteschlange und führt sie in einem einzelnen Hintergrundthread aus. Sie können dies leicht steuern, indem Sie es IntentServicedurch eine gleichwertige ServiceImplementierung ersetzen , möglicherweise wie diese .
  • Ähm, ich kann momentan an keine anderen denken

Vorteile:

  • Vermeidet das Problem des Kurzzeitgedächtnislecks
  • Wenn Ihre Aktivität während des Netzwerkbetriebs neu gestartet wird, kann sie das Ergebnis des Downloads weiterhin über ihre onActivityResultMethode erhalten
  • Bessere Plattform als AsyncTask zum Erstellen und Wiederverwenden von robustem Netzwerkcode. Beispiel: Wenn Sie einen wichtigen Upload durchführen müssen, können Sie dies AsyncTaskin einem tun. ActivityWenn 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 beenden Service.
  • Wenn Sie Ihre eigene gleichzeitige Version von IntentService(wie die oben verlinkte) verwenden, können Sie den Grad der Parallelität über die steuern Executor.

Implementierungszusammenfassung

Sie können IntentServiceganz 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 über IntentExtras heruntergeladen werden soll , und es übergeben PendingIntent, um das Ergebnis an Folgendes 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 re-use, 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 über die Aktivität auf und übergeben Sie ein PendingResult-Objekt, mit dem der Dienst das Ergebnis zurückgibt:

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 mit einem vollständig funktionierenden Android-Studio / Gradle-Projekt finden Sie hier .

Stevie
quelle
IntentService ist der richtige Weg, dies zu tun, nicht zu entwurzeln, da AsyncTask genau der Weg ist, dies nicht zu tun.
Brill Pappin
3
@BrillPappin Ich stimme fast vollständig zu und habe es neu formuliert, um die Nachteile von AsyncTask hervorzuheben. (Ich denke immer noch, dass es eine sehr kleine Anzahl von Fällen gibt, in denen es - wenn Sie wirklich wissen, was Sie tun - in Ordnung sein könnte , AsyncTask zu verwenden, aber die akzeptierte Antwort weist auf keine Nachteile hin und ist viel zu beliebt für das Gute von Android).
Stevie
1
Benötigen Sie tatsächlich IllustrativeRSS? Was ist, wenn Sie nicht mit RSS arbeiten?
Cullub
Meiner Meinung nach sollte Google die schlechte Implementierung der Garbage Collection ändern, anstatt den Berdon auf die Seite der Programmierer zu stellen. Dies liegt in der Verantwortung des Betriebssystems. Wenn ein Programmierer IntentService oder Service aufgrund des grundlegenden Problems bei der Android-Implementierung verwendet, wird Google nach einigen Jahren sagen, dass IntentService ebenfalls eine schlechte Praxis ist, und schlägt etwas anderes vor. Und diese Geschichte geht weiter ... Also sollten Google-Entwickler das schlechte Speichermanagement für Android lösen, nicht Programmierer.
Saeed Khalafinejad
Ich werde es nur sagen: Diese Antwort scheint eher eine Möglichkeit zu sein, das Projekt zu teilen, als eine bessere Alternative zu 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.
Verlassener Wagen
144

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.

Mark Allison
quelle
76
  1. Verwenden Sie nicht strictMode (nur im Debug-Modus)
  2. Ändern Sie nicht die SDK-Version
  3. Verwenden Sie keinen separaten Thread

Verwenden Sie Service oder AsyncTask

Siehe auch Stapelüberlauffrage:

android.os.NetworkOnMainThreadException Senden einer E-Mail von Android

venergiac
quelle
8
Hervorzuheben ist vielleicht, dass Sie bei Verwendung eines Dienstes immer noch einen separaten Thread erstellen müssen - Dienstrückrufe werden auf dem Hauptthread ausgeführt. Ein IntentService hingegen führt seine onHandleIntent-Methode in einem Hintergrundthread aus.
Stevie
Sie sollten keine AsyncTask für lange Betriebszeiten verwenden! Richtlinien geben max. 2 bis 3 Sekunden an.
Dage
76

Führen Sie die Netzwerkaktionen in einem anderen Thread aus

Zum Beispiel:

new Thread(new Runnable(){
    @Override
    public void run() {
        // Do network action in this function
    }
}).start();

Und fügen Sie dies zu AndroidManifest.xml hinzu

<uses-permission android:name="android.permission.INTERNET"/>
henry4343
quelle
5
Aber wie können wir herausfinden, wann der Thread in diesem beendet ist, damit wir die nächsten Aufgaben im UI-Thread ausführen können? Die AsyncTask bietet die Möglichkeit, dies zu tun. Gibt es eine Möglichkeit, dasselbe mit ausführbaren Threads zu tun?
Piyush Soni
3
Es wird Ihren Code Schritt für Schritt verarbeiten, so dass Sie am Ende des Codes den Handler zurück zum UI-Thread verwenden müssen
henry4343
1
Sie können einen asynchronen Task- oder Intent-Service verwenden, da dieser im Worker-Thread ausgeführt wird.
Chetan Chaudhari
64

Sie deaktivieren den strengen Modus mit folgendem Code:

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

Dies wird nicht empfohlen : Verwenden Sie die AsyncTaskSchnittstelle.

Vollständiger Code für beide Methoden

Sandeep
quelle
2
Ja, ein ANR-Fehler wäre aufgetreten. bedeutet, dass die App innerhalb von 5 Sekunden nicht reagiert.
Muhammad Mubashir
11
Das ist eine wirklich schlechte Antwort. Sie sollten die Richtlinien des Threads nicht ändern, sondern besseren Code schreiben: Führen Sie keine Netzwerkoperationen im Hauptthread durch!
Shkschneider
@ Sandeep Sie und andere Zuschauer sollten dies auch lesen. stackoverflow.com/a/18335031/3470479
Prakhar1001
54

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:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
Dhruv Jindal
quelle
Anonymous Runnable ist NICHT der beste Weg, da es einen impliziten Verweis auf die einschließende Klasse enthält und verhindert, dass sie GC-bearbeitet wird, bis der Thread abgeschlossen ist! Auch dieser Thread wird mit der gleichen Priorität wie der Haupt- / US-Thread ausgeführt und konkurriert mit Lebenszyklusmethoden und UI-Frameraten!
Yousha Aleayoub
49

Geben Sie Ihren Code ein:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();

Oder:

class DemoTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... arg0) {
        //Your implementation
    }

    protected void onPostExecute(Void result) {
        // TODO: do something with the feed
    }
}
Vaishali Sutariya
quelle
Der zweite ist der beste als der erste für API über 11
Rohit Goswami
46

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 .

Raihan Ahmed
quelle
46

Die Verwendung von Android-Anmerkungen ist eine Option. Sie können damit einfach eine beliebige Methode in einem Hintergrundthread ausführen:

// normal method
private void normal() {
    doSomething(); // do something in background
}

@Background
protected void doSomething() 
    // run your networking code here
}

Beachten Sie, dass es zwar Vorteile in Bezug auf Einfachheit und Lesbarkeit bietet, jedoch seine Nachteile hat.

Oleksiy
quelle
6
@Gavriel erstellt Duplikate von allem, was Sie mit Anmerkungen versehen, unabhängig davon, ob es sich um eine Methode, eine Aktivität, ein Fragment, einen Singleton usw. handelt. Es gibt also doppelt so viel Code und das Kompilieren dauert länger. Es kann auch einige Probleme aufgrund von Fehlern in der Bibliothek geben. Das Debuggen und Auffinden von Fehlern würde schwieriger werden.
Oleksiy
43

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 .

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {

    @Override
    public void onStart() {
        // Called before a request is started
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response) {
        // Called when response HTTP status is "200 OK"
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
        // Called when response HTTP status is "4XX" (for example, 401, 403, 404)
    }

    @Override
    public void onRetry(int retryNo) {
        // Called when request is retried
    }
});
Ashwin S Ashok
quelle
42

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 Handlerund übergeben Message.

Zur Vereinfachung der all diese Dinge, bietet Android verschiedene Art und Weise, wie AsyncTask, AsyncTaskLoader, CursorLoaderoder IntentService. Sie können diese also entsprechend Ihren Anforderungen verwenden.

Kapil Vats
quelle
40

Die Top- Antwort von spektom funktioniert perfekt.

Wenn Sie die AsyncTaskInline schreiben und nicht als Klasse erweitern, und obendrein eine Antwort aus der Klasse erhalten müssen AsyncTask, können Sie die folgende get()Methode verwenden.

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();

(Aus seinem Beispiel.)

sivag1
quelle
5
Verwenden get()ist eine schlechte Idee ... es macht AsyncTask wieder "synchronisieren"
Selvin
Gibt es einen besseren Ausweg? @ Selvin
sivag1
2
Ich denke, Sie könnten den Haupt-Thread über das Ergebnis informieren. Senden Sie beispielsweise eine Sendung mit dem Ergebnis an den Haupt-Thread.
Chine Gary
32

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!

Perry
quelle
28

Für mich war es das:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />

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:

<uses-permission android:name="android.permission.INTERNET"/>
rharvey
quelle
11
Lassen Sie mich Ihnen erklären, was Sie hier tun: NetworkOnMainThreadExceptionIst 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ß frei
Selvin
1
Ich habe auch diesen Ansatz gewählt und hatte keine Probleme. Guardian ist manchmal zu pingelig.
FractalBob
25

Verwenden Sie dies in Ihrer Aktivität

    btnsub.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub

                    //Initialize soap request + add parameters
                    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);

                    //Use this to add parameters
                    request.addProperty("pincode", txtpincode.getText().toString());
                    request.addProperty("bg", bloodgroup.getSelectedItem().toString());

                    //Declare the version of the SOAP request
                    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

                    envelope.setOutputSoapObject(request);
                    envelope.dotNet = true;

                    try {
                        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

                        //this is the actual part that will call the webservice
                        androidHttpTransport.call(SOAP_ACTION1, envelope);

                        // Get the SoapResult from the envelope body.
                        SoapObject result = (SoapObject) envelope.getResponse();
                        Log.e("result data", "data" + result);
                        SoapObject root = (SoapObject) result.getProperty(0);
                        // SoapObject s_deals = (SoapObject) root.getProperty(0);
                        // SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
                        //

                        System.out.println("********Count : " + root.getPropertyCount());

                        value = new ArrayList<Detailinfo>();

                        for (int i = 0; i < root.getPropertyCount(); i++) {
                            SoapObject s_deals = (SoapObject) root.getProperty(i);
                            Detailinfo info = new Detailinfo();

                            info.setFirstName(s_deals.getProperty("Firstname").toString());
                            info.setLastName(s_deals.getProperty("Lastname").toString());
                            info.setDOB(s_deals.getProperty("DOB").toString());
                            info.setGender(s_deals.getProperty("Gender").toString());
                            info.setAddress(s_deals.getProperty("Address").toString());
                            info.setCity(s_deals.getProperty("City").toString());
                            info.setState(s_deals.getProperty("State").toString());
                            info.setPinecode(s_deals.getProperty("Pinecode").toString());
                            info.setMobile(s_deals.getProperty("Mobile").toString());
                            info.setEmail(s_deals.getProperty("Email").toString());
                            info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
                            info.setAdddate(s_deals.getProperty("Adddate").toString());
                            info.setWaight(s_deals.getProperty("waight").toString());
                            value.add(info);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
                    //intent.putParcelableArrayListExtra("valuesList", value);

                    startActivity(intent);
                }
            }).start();
        }
    });
Dhiraj Kakran
quelle
23

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.)

Novak
quelle
22

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

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
amardeep
quelle
18

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:

http://api.example.com/stocks                       //ResponseWrapper<String> object containing a list of Srings with ticker symbols
http://api.example.com/stocks/$symbol               //Stock object
http://api.example.com/stocks/$symbol/prices        //PriceHistory<Stock> object
http://api.example.com/currencies                   //ResponseWrapper<String> object containing a list of currency abbreviation
http://api.example.com/currencies/$currency         //Currency object
http://api.example.com/currencies/$id1/values/$id2  //PriceHistory<Currency> object comparing the prices of the first currency (id1) to the second (id2)

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:

implementation 'com.squareup.retrofit2:retrofit:2.3.0' //retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' //gson serialization and deserialization support for retrofit, version must match retrofit version

FinancesApi.java

public interface FinancesApi {
    @GET("stocks")
    Call<ResponseWrapper<String>> listStocks();
    @GET("stocks/{symbol}")
    Call<Stock> getStock(@Path("symbol")String tickerSymbol);
    @GET("stocks/{symbol}/prices")
    Call<PriceHistory<Stock>> getPriceHistory(@Path("symbol")String tickerSymbol);

    @GET("currencies")
    Call<ResponseWrapper<String>> listCurrencies();
    @GET("currencies/{symbol}")
    Call<Currency> getCurrency(@Path("symbol")String currencySymbol);
    @GET("currencies/{symbol}/values/{compare_symbol}")
    Call<PriceHistory<Currency>> getComparativeHistory(@Path("symbol")String currency, @Path("compare_symbol")String currencyToPriceAgainst);
}

FinancesApiBuilder

public class FinancesApiBuilder {
    public static FinancesApi build(String baseUrl){
        return new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(FinancesApi.class);
    }
}

FinancesFragment-Snippet

FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
    @Override
    public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
        Stock stock = stockCall.body();
        //do something with the stock
    }
    @Override
    public void onResponse(Call<Stock> stockCall, Throwable t){
        //something bad happened
    }
}

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:

implementation 'com.android.volley:volley:1.0.0'

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:

public class ImageFetch {
    private static ImageLoader imageLoader = null;
    private static RequestQueue imageQueue = null;

    public static ImageLoader getImageLoader(Context ctx){
        if(imageLoader == null){
            if(imageQueue == null){
                imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
                Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }
                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }
        return imageLoader;
    }
}

user_view_dialog.xml

Fügen Sie Ihrer XML-Layoutdatei Folgendes hinzu, um ein Bild hinzuzufügen:

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/profile_picture"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    app:srcCompat="@android:drawable/spinner_background"/>

UserViewDialog.java

Fügen Sie der onCreate-Methode (Fragment, Activity) oder dem Konstruktor (Dialog) den folgenden Code hinzu:

NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());

Picasso

Eine weitere ausgezeichnete Bibliothek von Square. Auf der Website finden Sie einige gute Beispiele: http://square.github.io/picasso/

KG6ZVP
quelle
16

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:

  1. Sie müssen einen neuen Thread erstellen
  2. Oder verwenden Sie die AsyncTask-Klasse

Weg:

Legen Sie alle Ihre Werke hinein

  1. run() Methode des neuen Threads
  2. Oder doInBackground() 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?

  1. Aktualisieren Sie bei Verwendung von AsyncTask die Ansicht von der onPostExecute()Methode
  2. Oder rufen Sie die runOnUiThread()Methode auf und aktualisieren Sie die Ansicht innerhalb der run()Methode.
Nabin
quelle
12

Sie sind in der Lage , einen Teil des Codes in einen anderen Thread bewegen die abzuladen main threadund 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

Java-Threads werden nur einmal verwendet und sterben nach Ausführung der Ausführungsmethode.

HandlerThread ist eine praktische Klasse zum Starten eines neuen Threads mit einem Looper.

AsyncTask

AsyncTask wurde als Hilfsklasse für Thread und Handler entwickelt und stellt kein generisches Threading-Framework dar. AsyncTasks sollten idealerweise für kurze Vorgänge (höchstens einige Sekunden) verwendet werden. Wenn Sie Threads über einen längeren Zeitraum laufen lassen müssen, wird dringend empfohlen, die verschiedenen APIs zu verwenden, die vom Paket java.util.concurrent bereitgestellt werden, z Executor , ThreadPoolExecutor und FutureTask .

Thread-Pool-Implementierung ThreadPoolExecutor , ScheduledThreadPoolExecutor ...

ThreadPoolExecutor-Klasse, die ExecutorService implementiert, die eine genaue Kontrolle über den Thread-Pool ermöglicht (z. B. Größe des Kernpools, maximale Poolgröße, Keep-Alive-Zeit usw.)

ScheduledThreadPoolExecutor - eine Klasse, die ThreadPoolExecutor erweitert. Es kann Aufgaben nach einer bestimmten Verzögerung oder in regelmäßigen Abständen planen.

FutureTask

FutureTask führt eine asynchrone Verarbeitung durch. Wenn das Ergebnis jedoch noch nicht fertig ist oder die Verarbeitung noch nicht abgeschlossen ist, blockiert der Aufruf von get () den Thread

AsyncTaskLoaders

AsyncTaskLoader lösen viele Probleme, die AsyncTask inhärent sind

IntentService

Dies ist die Standardoption für die Verarbeitung mit langer Laufzeit unter Android. Ein gutes Beispiel wäre das Hochladen oder Herunterladen großer Dateien. Das Hoch- und Herunterladen kann auch dann fortgesetzt werden, wenn der Benutzer die App beendet und Sie den Benutzer auf keinen Fall daran hindern möchten, die App während dieser Aufgaben zu verwenden.

JobScheduler

Tatsächlich müssen Sie mit JobInfo.Builder einen Service erstellen und einen Job erstellen, der Ihre Kriterien für die Ausführung des Service angibt.

RxJava

Bibliothek zum Erstellen asynchroner und ereignisbasierter Programme unter Verwendung beobachtbarer Sequenzen.

Coroutinen (Kotlin)

Das Wesentliche dabei ist, dass asynchroner Code so ähnlich wie synchron aussieht

Lesen Sie hier , hier , hier , hier mehr

yoAlex5
quelle
Hat für mich funktioniert ... Ich habe AsyncTask ausgiebig verwendet, aber wenn eine Aufgabe ausgeführt wird, wartet eine andere. Ich möchte das lösen. Jetzt arbeite ich mit executeonexecutor. Mal sehen, wie es sich auf Geräten mit wenig Speicher verhält.
Suraj Shingade
Bitte werfen Sie einen Blick auf die Methode: asyncTask.executeOnExecutor (AsyncTask.THREAD_POOL_EXECUTOR, params); um Ihre Aufgabe gleichzeitig
auszuführen
10

Obwohl es oben einen riesigen Lösungspool gibt, erwähnte niemand com.koushikdutta.ion: https://github.com/koush/ion

Es ist auch asynchron und sehr einfach zu bedienen:

Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
   @Override
    public void onCompleted(Exception e, JsonObject result) {
        // do stuff with the result or error
    }
});
msysmilu
quelle
10

Neue Threadund AsyncTask- Lösungen wurden bereits erläutert.

AsyncTasksollte idealerweise für kurze Operationen verwendet werden. Normal Threadist für Android nicht vorzuziehen.

Schauen Sie sich eine alternative Lösung mit HandlerThread und Handler an

HandlerThread

Praktische Klasse zum Starten eines neuen Threads mit einem Looper. Der Looper kann dann zum Erstellen von Handlerklassen verwendet werden. Beachten Sie, dass start()noch aufgerufen werden muss.

Handler:

Mit einem Handler können Sie Nachrichten- und ausführbare Objekte senden und verarbeiten, die der MessageQueue eines Threads zugeordnet sind. Jede Handler-Instanz ist einem einzelnen Thread und der Nachrichtenwarteschlange dieses Threads zugeordnet. Wenn Sie einen neuen Handler erstellen, wird dieser an die Thread- / Nachrichtenwarteschlange des Threads gebunden, der ihn erstellt. Ab diesem Zeitpunkt werden Nachrichten und ausführbare Dateien an diese Nachrichtenwarteschlange gesendet und ausgeführt, sobald sie aus der Nachricht herauskommen Warteschlange.

Lösung:

  1. Erstellen HandlerThread

  2. Rufen Sie start()anHandlerThread

  3. Erstellen Sie, Handlerindem sie LooperausHanlerThread

  4. Betten Sie Ihren Code für den Netzwerkbetrieb in das RunnableObjekt ein

  5. RunnableAufgabe senden anHandler

Beispielcode-Snippet, welche Adresse NetworkOnMainThreadException

HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Ravi", "Before IO call");
            URL page = new URL("http://www.google.com");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ( (line =  buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Ravi", "After IO call");
            Log.d("Ravi",text.toString());

        }catch( Exception err){
            err.printStackTrace();
        }
    }
};
mainHandler.post(myRunnable);

Vorteile dieses Ansatzes:

  1. Das Erstellen neuer Dateien Thread/AsyncTaskfür jeden Netzwerkbetrieb ist teuer. Das Thread/AsyncTaskwird zerstört und für den nächsten Netzwerkbetrieb neu erstellt. Mit Handlerund HandlerThreadAnsatz können Sie jedoch viele Netzwerkvorgänge (als ausführbare Aufgaben) HandlerThreadmithilfe von an einzelne senden Handler.
Ravindra Babu
quelle
8

RxAndroidist 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.

Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() { 

  @Override 
  public List<String> call() { 
    return mRestClient.getFavoriteMusicShows(); 
  }
});

mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {

    @Override 
    public void onCompleted() { }

    @Override 
    public void onError(Throwable e) { }

    @Override 
    public void onNext(List<String> musicShows){
        listMusicShows(musicShows);
    }
});
  1. Durch Angabe (Schedulers.io())wird RxAndroid getFavoriteMusicShows() auf einem anderen Thread ausgeführt.

  2. Mit verwenden AndroidSchedulers.mainThread()möchten wir diese Observable im UI-Thread beobachten, dh wir möchten, dass unser onNext()Rückruf im UI-Thread aufgerufen wird

Shinoo Goyal
quelle
8

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

StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);

Oder erstellen Sie einen einfachen Handler und aktualisieren Sie den Hauptthread, wenn Sie möchten.

Runnable runnable;
Handler newHandler;

newHandler = new Handler();
runnable = new Runnable() {
    @Override
    public void run() {
         try {
            //update UI
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
};
newHandler.post(runnable);

Und um den Thread zu stoppen, verwenden Sie:

newHandler.removeCallbacks(runnable);

Weitere Informationen finden Sie hier: Schmerzloses Einfädeln

Sharath Kumar
quelle
Danke. Version 1 hilft beim Hinzufügen als erste Aktion in onCreate.
Ingo
7

Das funktioniert. Ich habe gerade Dr.Luijis Antwort etwas einfacher gemacht.

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
Kacy
quelle
7

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.

Ponsuyambu Velladurai
quelle
7

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.

RevanthKrishnaKumar V.
quelle