Vraag Hoe los ik android.os.NetworkOnMainThreadException?


Ik kreeg een fout tijdens het uitvoeren van mijn Android-project voor RssReader.

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();

En het toont de onderstaande fout:

android.os.NetworkOnMainThreadException

Hoe kan ik dit probleem oplossen?


1969
2018-06-14 12:02


oorsprong


antwoorden:


Deze uitzondering wordt gegenereerd wanneer een toepassing probeert een netwerkbewerking uit te voeren op de hoofdthread. Voer je code 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
    }
}

Hoe de taak uit te voeren:

In MainActivity.java bestand kunt u deze regel toevoegen binnen uw oncreate() methode

new RetrieveFeedTask().execute(urlToRssFeed);

Vergeet dit niet toe te voegen AndroidManifest.xml het dossier:

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

2232
2018-06-14 12:15



U moet bijna altijd netwerkbewerkingen uitvoeren op een thread of als een asynchrone taak.

Maar het is mogelijk om deze beperking te verwijderen en u overschrijft het standaardgedrag als u bereid bent de gevolgen te aanvaarden.

Toevoegen:

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

StrictMode.setThreadPolicy(policy); 

In jouw klas,

en

VOEG deze toestemming toe in het Android manifest.xml bestand:

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

gevolgen:

Uw app zal (in gebieden met vlekkerige internetverbindingen) niet meer reageren en vastlopen, de gebruiker merkt traagheid en moet een force kill uitvoeren, en u riskeert dat de activiteitsbeheerder uw app vermoord en de gebruiker vertelt dat de app is gestopt.

Android heeft enkele goede tips over goede programmeerpraktijken om te ontwerpen voor reactievermogen: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


556
2018-02-15 06:59



Ik heb dit probleem opgelost met een nieuwe Thread.

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

346
2018-01-21 16:31



U kunt geen netwerk uitvoeren IO op de UI-thread aan Honingraat. Technisch gezien is mogelijk in eerdere versies van Android, maar het is een heel slecht idee, omdat uw app hierdoor niet meer reageert en het besturingssysteem uw app kan doden omdat deze zich slecht gedraagt. U moet een achtergrondproces uitvoeren of AsyncTask gebruiken om uw netwerktransactie uit te voeren op een achtergrondthread.

Er is een artikel over Pijnloos draadsnijden op de Android-ontwikkelaarssite die een goede inleiding is op deze, en het geeft je een veel betere diepte van een antwoord dan hier realistisch kan worden geboden.


124
2018-06-14 12:07



Het geaccepteerde antwoord heeft enkele belangrijke nadelen. Het is niet aan te raden om AsyncTask te gebruiken voor netwerken tenzij u werkelijk weet wat je doet. Enkele van de nadelen zijn:

  • AsyncTask's gemaakt als niet-statische interne klassen hebben een impliciete verwijzing naar het omsluitende activiteitsobject, de context en de volledige weergavehiërarchie die door die activiteit is gemaakt. Deze verwijzing voorkomt dat de activiteit wordt verzameld totdat het achtergrondwerk van de AsyncTask is voltooid. Als de verbinding van de gebruiker traag is en / of de download groot is, kunnen deze kortetermijngeheugenlekken een probleem worden - bijvoorbeeld als de richting verschillende keren wordt gewijzigd (en u de uitvoeringstaken niet annuleert) of als de gebruiker navigeert weg van de activiteit.
  • AsyncTask heeft verschillende uitvoeringskenmerken, afhankelijk van het platform waarop het wordt uitgevoerd: vóór API niveau 4 worden AsyncTasks serieel uitgevoerd op een enkele achtergrondthread; van API level 4 tot en met API level 10, voert AsyncTasks uit op een pool van maximaal 128 threads; vanaf API level 11 AsyncTask voert serieel uit op een enkele achtergrondthread (tenzij u de overbelaste gebruikt executeOnExecutormethode en lever een alternatieve executeur aan). Code die goed werkt als deze serieel op ICS wordt uitgevoerd, kan breken wanneer deze gelijktijdig op Gingerbread wordt uitgevoerd, bijvoorbeeld als u onbedoelde afhankelijkheid van orderuitvoering hebt.

Als u korte-termijngeheugenlekken wilt voorkomen, goed gedefinieerde uitvoeringskenmerken op alle platforms wilt hebben en een basis hebt om een ​​zeer robuuste netwerkverwerking te bouwen, kunt u overwegen:

  1. Met behulp van een bibliotheek die dit goed voor je doet - er is een leuke vergelijking van networking libs in deze vraagof
  2. Gebruik maken van een Service of IntentService in plaats daarvan, misschien met een PendingIntent om het resultaat terug te sturen via de activiteiten onActivityResult methode.

IntentService-aanpak

Down-kanten:

  • Meer code en complexiteit dan AsyncTask, hoewel niet zoveel als je zou denken
  • Zullen verzoeken in wachtrij plaatsen en uitvoeren op a single achtergronddraad. U kunt dit gemakkelijk regelen door te vervangen IntentService met een equivalent Service implementatie, misschien zoals deze.
  • Eh, ik kan op dit moment eigenlijk geen anderen bedenken

Up-kanten:

  • Vermijdt het lekprobleem op korte termijn geheugen
  • Als uw activiteit opnieuw wordt gestart terwijl netwerkbewerkingen tijdens de vlucht plaatsvinden, kan het nog steeds het resultaat van de download ontvangen via de onActivityResult methode
  • Beter platform dan AsyncTask om robuuste netwerkcode te bouwen en opnieuw te gebruiken. Voorbeeld: als u een belangrijke upload moet doen, kunt u dit doen AsyncTask in een Activity, maar als de gebruikerscontext-uit de app schakelt om een ​​telefoongesprek te voeren, het systeem mei kill de app voordat het uploaden is voltooid. Het is minder waarschijnlijk om een ​​applicatie te doden met een actieve Service.
  • Als u uw eigen gelijktijdige versie van gebruikt IntentService (zoals degene die ik hierboven heb gelinkt) kunt u het niveau van concurrency regelen via de Executor.

Implementatiesamenvatting

U kunt een IntentService om vrij eenvoudig downloads op een enkele thread uit te voeren.

Stap 1: Maak een IntentService om de download uit te voeren. Je kunt het vertellen via wat je moet downloaden Intent extra's, en geef het door PendingIntent gebruiken om het resultaat terug te geven aan de 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);
        }
    }
}

Stap 2: registreer de service in het manifest:

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

Stap 3: Roep de service van de activiteit aan en geef een PendingResult-object door dat door de service wordt gebruikt om het resultaat te retourneren:

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

Stap 4: Behandel het resultaat 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);
}

Een github-project met een volledig werkend Android-Studio / gradle-project is beschikbaar hier.


118
2018-01-22 13:17



  1. Gebruik strictMode niet (alleen in debug-modus)
  2. Wijzig de SDK-versie niet
  3. Gebruik geen afzonderlijke thread

Gebruik Service of AsyncTask

Zie ook Stack Overflow-vraag:

android.os.NetworkOnMainThreadException verzenden van een e-mail van Android


59
2017-08-18 09:18



Voer de netwerkacties uit op een andere thread

Bijvoorbeeld:

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

En voeg dit toe aan AndroidManifest.xml

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

51
2017-12-24 14:33



U schakelt de strikte modus uit met behulp van de volgende code:

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

Dit wordt niet aanbevolen: gebruik de AsyncTaskinterface.

Volledige code voor beide methoden


46
2017-10-24 07:10