Jak naprawić " android.os.Networkkonmainthreadexception"?

Dostałem błąd podczas uruchamiania mojego projektu Android dla RssReader.

Kod:

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

I pokazuje poniższy błąd:

android.os.NetworkOnMainThreadException

Jak mogę rozwiązać ten problem?

Author: Samet ÖZTOPRAK, 2011-06-14

30 answers

Uwaga: AsyncTask został wycofany z poziomu API 30.
https://developer.android.com/reference/android/os/AsyncTask

Ten wyjątek jest wyrzucany, gdy aplikacja próbuje wykonać operację sieciową w swoim głównym wątku. Uruchom swój kod w 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
    }
}

Jak wykonać zadanie:

W pliku MainActivity.java możesz dodać tę linię w swojej metodzie oncreate()

new RetrieveFeedTask().execute(urlToRssFeed);

Nie zapomnij dodać tego do AndroidManifest.xml pliku:

<uses-permission android:name="android.permission.INTERNET"/>
 2604
Author: Michael Spector,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-08 07:02:44

Prawie zawsze należy uruchamiać operacje sieciowe w wątku lub jako zadanie asynchroniczne.

Ale jest możliwe usunięcie tego ograniczenia i nadpisanie domyślnego zachowania, jeśli chcesz zaakceptować konsekwencje.

Dodaj:

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

StrictMode.setThreadPolicy(policy); 

W twojej klasie,

I

Dodaj to uprawnienie w manifeście Androida.plik xml:

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

Konsekwencje:

Twoja aplikacja (w obszarach spotty połączenia z Internetem) stanie się użytkownik odczuwa powolność i musi zabić siłą, a ty ryzykujesz, że menedżer aktywności zabije Twoją aplikację i poinformuje użytkownika, że aplikacja została zatrzymana.

Android ma kilka dobrych wskazówek na temat dobrych praktyk programistycznych, aby zaprojektować responsywność: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

 713
Author: user1169115,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-11 14:18:49

Rozwiązałem ten problem używając nowego Thread.

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
 457
Author: Dr.Luiji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 09:42:24

Zaakceptowana odpowiedź ma kilka znaczących minusów. Nie jest wskazane, aby używać AsyncTask do sieci, chyba że naprawdę wiesz, co robisz. Niektóre z dolnych stron to:

  • AsyncTask utworzone jako niestatyczne klasy wewnętrzne mają ukryte odniesienie do otaczającego obiektu Activity, jego kontekstu i całej hierarchii widoków utworzonej przez tę aktywność. To odniesienie zapobiega zbieraniu śmieci do momentu, gdy AsyncTask ' s praca w tle zakończona. Jeśli połączenie użytkownika jest wolne i / lub pobieranie jest Duże, te krótkotrwałe wycieki pamięci mogą stanowić problem - na przykład, jeśli orientacja zmienia się kilka razy (i nie anulujesz wykonywanych zadań) lub użytkownik odchodzi od aktywności.
  • AsyncTask ma różne właściwości wykonawcze w zależności od platformy, na której jest wykonywany: przed poziomem API 4 AsyncTask wykonuje się seryjnie na jednym wątku tła; od poziomu API 4 poprzez AsyncTask na poziomie API 10, uruchamia się na puli do 128 wątków; począwszy od poziomu API 11, AsyncTask wykonuje seryjnie na jednym wątku tła (chyba że użyjesz przeciążonej metody executeOnExecutor i dostarczysz alternatywnego executora). Kod, który działa dobrze, gdy działa seryjnie na ICS, może pęknąć, gdy jest wykonywany jednocześnie na Gingerbread, powiedzmy, jeśli masz nieumyślne zależności kolejności wykonania.

Jeśli chcesz uniknąć wycieków pamięci krótkotrwałej, miej dobrze zdefiniowane wykonanie cechy na wszystkich platformach i mają podstawę do zbudowania naprawdę solidnej obsługi sieci, warto rozważyć: {]}

    W tym kontekście warto zwrócić uwagę na to, że w przypadku bibliotek sieciowych, które nie są w pełni kompatybilne z bibliotekami sieciowymi.]}
  1. używając zamiast tego Service lub IntentService, być może za pomocą PendingIntent, aby zwrócić wynik za pomocą metody onActivityResult działania.

podejście IntentService

Dół-boki:

  • więcej kod i złożoność niż AsyncTask, choć nie tak bardzo, jak mogłoby się wydawać [31]}
  • ustawia żądania w kolejce i uruchamia je napojedynczym wątku w tle. Można to łatwo kontrolować, zastępując IntentService równoważną implementacją Service, Być może jak ta .
  • Nie mogę teraz myśleć o innych.]}

Up-sides:

  • unika problemu z wyciekiem pamięci krótkotrwałej
  • Jeśli aktywność zostanie uruchomiona ponownie podczas operacji sieciowych są w locie może nadal otrzymywać wynik pobrania za pomocą metody onActivityResult
  • lepsza Platforma niż AsyncTask do budowania i ponownego wykorzystania solidnego kodu sieciowego. Przykład: jeśli musisz wykonać ważne przesłanie, możesz to zrobić z AsyncTask W Activity, ale jeśli kontekst użytkownika wyłączy się z aplikacji, aby wykonać połączenie telefoniczne, system Może zabić aplikację przed zakończeniem przesyłania. Jest mniej prawdopodobne, aby zabić aplikację z aktywnym Service.
  • Jeśli używasz twoja własna współbieżna wersja IntentService (jak ta, którą podlinkowałem powyżej) możesz kontrolować poziom współbieżności za pomocą Executor.

podsumowanie realizacji

Możesz zaimplementować IntentService, aby dość łatwo pobierać pliki w jednym wątku tła.

Krok 1: Utwórz IntentService, aby wykonać pobieranie. Możesz powiedzieć, co pobrać za pomocą Intent extra ' s, i przekazać go PendingIntent, aby użyć do powrotu wyniku do 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);
        }
    }
}

Krok 2: Rejestracja służba w manifeście:

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

Krok 3: wywołaj usługę z aktywności, przekazując obiekt PendingResult, którego usługa użyje do zwrócenia wyniku:

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

Krok 4: obsłuż wynik w 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);
}

Projekt Github zawierający kompletny działający projekt Android-Studio/Gradle jest dostępny tutaj .

 180
Author: Stevie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-25 11:54:17

Nie można wykonać sieci I/Ow wątku UI na Honeycomb. Technicznie rzecz biorąc, to jest możliwe we wcześniejszych wersjach Androida, ale jest to naprawdę zły pomysł, ponieważ spowoduje to, że aplikacja przestanie odpowiadać i może spowodować, że system operacyjny zabije Twoją aplikację za złe zachowanie. Musisz uruchomić proces w tle lub użyć funkcji AsyncTask, aby wykonać transakcję sieciową w wątku w tle.

Jest artykuł o bezbolesne Gwintowanie na Androida strona dewelopera, która jest dobrym wstępem do tego, i zapewni Ci znacznie lepszą głębię odpowiedzi, niż można realistycznie podać tutaj.

 147
Author: Mark Allison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 16:25:22

Istnieją dwa rozwiązania tego problemu.

1) nie zapisuj połączenia sieciowego w głównym wątku UI, Użyj do tego zadania asynchronicznego.

2) zapisz poniższy kod do pliku MainActivity po setContentView (R. layout.activity_main);

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

I poniżej instrukcja Importuj do pliku java.

import android.os.StrictMode;
 121
Author: Dipak Keshariya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-30 10:12:17

Wykonaj akcje sieciowe na innym wątku

Na Przykład:

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

I dodaj to do AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
 83
Author: henry4343,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-13 19:49:55
  1. nie używaj strictMode (tylko w trybie debugowania)
  2. nie zmieniaj wersji SDK
  3. nie używaj osobnego wątku

Użyj usługi lub AsyncTask

Zobacz też pytanie o przepełnienie stosu:

android.os.NetworkOnMainThreadException wysyłanie wiadomości e-mail z Androida

 80
Author: venergiac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:38

Wyłączasz tryb ścisły używając następującego kodu:

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

Nie jest to zalecane : Użyj interfejsu AsyncTask.

Pełny kod dla obu metod

 71
Author: Piyush-Ask Any Difference,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-08 06:59:30

Operacje sieciowe nie mogą być uruchamiane w głównym wątku. Musisz uruchomić wszystkie zadania sieciowe w wątku podrzędnym lub zaimplementować AsyncTask.

Tak uruchamiasz zadanie w wątku potomnym:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
 59
Author: Dhruv Jindal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 21:08:38

Wpisz swój kod w środku:

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

Lub:

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
    }
}
 51
Author: Vaishali Sutariya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 21:13:15

To się dzieje w Androidzie 3.0 i nowszych. Od Androida 3.0 i nowszych, mają ograniczone korzystanie z operacji sieciowych (funkcje, które uzyskują dostęp do Internetu) od uruchomienia w głównym wątku / wątku UI (co powstaje z Twoich metod on create i on CV w aktywności).

Ma to zachęcić do używania oddzielnych wątków do operacji sieciowych. Zobacz AsyncTask Aby uzyskać więcej informacji na temat prawidłowego wykonywania działań sieciowych.

 49
Author: raihan ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 16:27:30

Użycie adnotacji Androida {[3] } jest opcją. Pozwoli Ci to po prostu uruchomić dowolną metodę w wątku w tle:

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

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

Zauważ, że chociaż zapewnia zalety prostoty i czytelności, ma swoje wady.

 48
Author: Oleksiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 16:46:11

Błąd jest spowodowany wykonywaniem długich operacji w głównym wątku,możesz łatwo naprawić problem za pomocą Asyntask lub Thread . Możesz sprawdzić tę bibliotekę AsyncHTTPClient dla lepszej obsługi.

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
    }
});
 44
Author: Ashwin S Ashok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 04:53:07

Nie powinieneś wykonywać żadnych czasochłonnych zadań na głównym wątku (wątku UI), takich jak operacje sieciowe, wejścia/wyjścia plików lub operacje bazy danych SQLite. Tak więc w przypadku tego rodzaju operacji należy utworzyć wątek roboczy, ale problem polega na tym, że nie można bezpośrednio wykonać żadnej operacji związanej z interfejsem użytkownika z wątku roboczego. W tym celu należy użyć Handler i przekazać Message.

Aby uprościć te wszystkie rzeczy, Android zapewnia różne sposoby, takie jak AsyncTask, AsyncTaskLoader, CursorLoader lub IntentService. Więc możesz użyć dowolnego z nich zgodnie z Twoimi wymaganiami.

 43
Author: Kapil Vats,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 16:29:41

[[4]}top odpowiedź spektom działa idealnie.

Jeśli piszesz AsyncTask inline i nie rozszerzasz jako klasa, a ponadto, jeśli istnieje potrzeba uzyskania odpowiedzi z AsyncTask, można użyć metody get(), Jak Poniżej.

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

(z jego przykładu.)

 42
Author: sivag1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:29

Jest to rzucane tylko dla aplikacji ukierunkowanych na plaster miodu SDK lub wyższy. Aplikacje obsługujące wcześniejsze wersje SDK mogą tworzyć sieć w swoich głównych wątkach pętli zdarzeń.

Błąd to Ostrzeżenie SDK!

 32
Author: perry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 21:09:34

Dla mnie było tak:

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

Urządzenie, na którym testowałem moją aplikację, to 4.1.2, czyli SDK w wersji 16!

Upewnij się, że wersja docelowa jest taka sama jak Biblioteka docelowa Androida. Jeśli nie jesteś pewien, jaka jest twoja docelowa biblioteka, kliknij prawym przyciskiem myszy projekt - > buduj ścieżkę -> Android, i to powinien być ten, który jest zaznaczony.

Również, jak inni wspominali, Dołącz prawidłowe uprawnienia dostępu do Internetu:

<uses-permission android:name="android.permission.INTERNET"/>
 28
Author: rharvey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 21:07:28

Użyj tego w swojej aktywności

    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();
        }
    });
 25
Author: dhiraj kakran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-03 12:07:24

Po prostu wymówić coś wprost:

Główny wątek to w zasadzie wątek interfejsu użytkownika.

Więc mówienie, że nie możesz wykonywać operacji sieciowych w głównym wątku oznacza, że nie możesz wykonywać operacji sieciowych w wątku UI, co oznacza, że nie możesz wykonywać operacji sieciowych w bloku *runOnUiThread(new Runnable() { ... }* wewnątrz innego wątku.

(po prostu miałem długą chwilę drapania głową próbując dowiedzieć się, dlaczego dostaję ten błąd gdzieś indziej niż mój główny wątek. To dlaczego; ten wątek pomógł; i mam nadzieję, że ten komentarz pomoże komuś innemu.)

 24
Author: Novak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-24 21:32:53

Ten wyjątek występuje z powodu ciężkich zadań wykonywanych w głównym wątku, jeśli to zadanie zajmuje zbyt dużo czasu .

Aby tego uniknąć, możemy obsłużyć to za pomocą wątków lub executerów

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
 22
Author: amardeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 21:12:36

Istnieje wiele świetnych odpowiedzi na to pytanie, ale wiele świetnych bibliotek pojawiło się od czasu opublikowania tych odpowiedzi. Jest to swego rodzaju przewodnik dla początkujących.

Omówię kilka przypadków użycia do wykonywania operacji sieciowych i rozwiązanie lub dwa dla każdego.

Odpoczynek przez HTTP

zazwyczaj Json, może być XML lub coś innego

Pełny dostęp do API

Załóżmy, że piszesz aplikację, która pozwala użytkownikom śledzić ceny akcji, stopy procentowe i kursy walut. Znajdziesz API Json, które wygląda mniej więcej tak:

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)

Modernizacja z kwadratu

Jest to doskonały wybór dla API z wieloma punktami końcowymi i pozwala zadeklarować pozostałe punkty końcowe zamiast konieczności kodowania ich indywidualnie, jak w przypadku innych bibliotek, takich jak ion lub Volley. (strona internetowa: http://square.github.io/retrofit/)

Jak to wykorzystać w finansach API?

Buduj.gradle

Dodaj te linie do buid poziomu modułu.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
    }
}

Jeśli Twoje API wymaga klucza API lub innego nagłówka, takiego jak token użytkownika itp. aby zostać wysłanym, modernizacja ułatwia to (zobacz tę niesamowitą odpowiedź po szczegóły: https://stackoverflow.com/a/42899766/1024412).

Jednorazowy dostęp do ReST API

Załóżmy, że budujesz aplikację "Pogoda nastroju", która sprawdza lokalizację GPS użytkowników i sprawdza aktualną temperaturę w tym obszarze i informuje ich o nastroju. Tego typu aplikacja nie musi deklarować punktów końcowych API; musi tylko mieć dostęp do jednego punktu końcowego API.

Ion

Jest to świetna biblioteka dla tego typu dostępu.

Proszę przeczytać msysmilu ' s great odpowiedź ( https://stackoverflow.com/a/28559884/1024412 )

Ładowanie obrazów przez HTTP

Volley

Volley może być również używany do ReST API, ale ze względu na bardziej skomplikowaną wymaganą konfigurację wolę używać Retrofit z kwadratu jak wyżej (http://square.github.io/retrofit/)

Załóżmy, że budujesz aplikację społecznościową i chcesz załadować zdjęcia profilowe znajomych.

Buduj.gradle

Dodaj ten wiersz do Twój buid poziomu modułu.gradle:

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

ImageFetch.java

Volley wymaga więcej konfiguracji niż modernizacji. Będziesz musiał utworzyć taką klasę, aby skonfigurować RequestQueue, ImageLoader i ImageCache, ale nie jest tak źle: {]}

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

Dodaj następujący plik XML układu, aby dodać obraz:

<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

Dodaj następujący kod do metody onCreate (Fragment, Activity) lub konstruktor (Dialog):

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

Picasso

[[9]}kolejna wspaniała biblioteka od Square. Zajrzyj na stronę, aby zobaczyć kilka świetnych przykładów: http://square.github.io/picasso/
 19
Author: KG6ZVP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 08:26:37

W prostych słowach,

NIE WYKONUJ PRACY SIECIOWEJ W WĄTKU UI

Na przykład, jeśli wykonasz żądanie HTTP, jest to akcja sieciowa.

Rozwiązanie:

  1. musisz utworzyć nowy wątek
  2. lub użyj klasy AsyncTask

Sposób:

Włóż wszystkie swoje prace do środka

  1. run() metoda nowego wątku
  2. lub doInBackground() Metoda AsyncTask klasy.

Ale:

Gdy otrzymasz coś z odpowiedzi sieci i chcesz pokazać to w widoku (np. wyświetl komunikat odpowiedzi w TextView), musisz wrócić z powrotem do wątku UI.

Jeśli tego nie zrobisz, dostaniesz ViewRootImpl$CalledFromWrongThreadException.

Jak?

  1. podczas korzystania z AsyncTask, Aktualizuj widok z metody onPostExecute()
  2. lub wywołanie runOnUiThread() metoda i widok aktualizacji wewnątrz metody run().
 16
Author: Nabin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:45

Możesz przenieść część kodu do innego wątku, aby odciążyć main thread i uniknąć uzyskania ANR, NetworkOnMainThreadException, IllegalStateException (np. nie może uzyskać dostępu do bazy danych w głównym wątku, ponieważ może potencjalnie zablokować interfejs użytkownika na długi okres czasu).

Są pewne podejścia, które powinieneś wybrać, zależy od sytuacji

Java Thread lub Android HandlerThread

Java threads are jednorazowe użycie i śmierć po wykonaniu jego metody run.

HandlerThread jest poręczną klasą do uruchamiania nowego wątku, który ma looper.

AsyncTask (nieaktualne na poziomie API 30)

AsyncTask jest zaprojektowana jako klasa pomocnicza wokół Thread i Handler i nie stanowi ogólnego frameworka wątków. Asynchroniczne zadania powinny być idealnie używane do krótkich operacji (maksymalnie kilka sekund.) Jeśli potrzebujesz utrzymuj wątki działające przez długi czas, zaleca się korzystanie z różnych interfejsów API dostarczanych przez Javę.util.współbieżny pakiet np. Executor, ThreadPoolExecutor i FutureTask .

Ponieważ główny wątek monopolizuje komponenty interfejsu użytkownika, nie jest możliwy dostęp do niektórych widoków, dlatego Handler jest na ratunku

Implementacja puli wątków ThreadPoolExecutor , ScheduledThreadPoolExecutor ...

Klasa ThreadPoolExecutor, która implementuje ExecutorService, która daje dokładną kontrolę nad pulą wątków (np. rozmiar puli rdzenia, maksymalny rozmiar puli, czas życia itp.)

ScheduledThreadPoolExecutor-Klasa rozszerzająca ThreadPoolExecutor. Może planować zadania po danym opóźnieniu lub okresowo.

FutureTask

FutureTask wykonuje przetwarzanie asynchroniczne, jeśli jednak wynik nie jest gotowy Jednak lub przetwarzanie nie zostało zakończone, wywołanie get() spowoduje zablokowanie wątku

AsyncTaskLoaders

Asynctaskloadery rozwiązują wiele problemów, które są nieodłączne dla AsyncTask.]}

IntentService

Jest to wybór defacto dla długotrwałego przetwarzania na Androida, dobrym przykładem może być przesyłanie lub pobieranie dużych plików. Przesyłanie i pobieranie może być kontynuowane, nawet jeśli użytkownik opuści aplikację, a na pewno nie chcesz zablokować użytkownikowi możliwość korzystania z aplikacji podczas wykonywania tych zadań.

JobScheduler

Skutecznie, trzeba utworzyć usługę i utworzyć zadanie za pomocą JobInfo.Kreator, który określa kryteria, kiedy należy uruchomić usługę.

RxJava

Biblioteka do komponowania programów asynchronicznych i opartych na zdarzeniach za pomocą obserwowalnych sekwencji.

Koroutines (Kotlin)

The główną jego istotą jest to, że sprawia, że kod asynchroniczny wygląda tak samo jak synchroniczny

Czytaj więcej tutaj, Proszę., Proszę., tutaj

 12
Author: yoAlex5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-18 11:41:51

Nowe rozwiązania Threadi AsyncTask zostały już wyjaśnione.

AsyncTask idealnie nadaje się do krótkich operacji. Normal Thread nie jest korzystne dla Androida.

Spójrz na alternatywne rozwiązanie za pomocą HandlerThread i Handler

HandlerThread

Poręczna Klasa do uruchamiania nowego wątku z looperem. Looper może być następnie użyty do tworzenia klas obsługi. Zauważ, że start() musi być dzwoniłem.

Obsługa pozwala na wysyłanie i przetwarzanie wiadomości i obiektów, które można uruchomić, związanych z wiadomością w wątku. Każda instancja obsługi jest powiązana z pojedynczym wątkiem i kolejką wiadomości tego wątku. Kiedy tworzysz nową funkcję obsługi, jest ona powiązana z kolejką wątków / wiadomości wątku, który ją tworzy - od tego momentu będzie ona dostarczać wiadomości i pliki uruchamiające do tej kolejki i wykonywać je w miarę ich wychodzenia kolejki komunikatów.

Rozwiązanie:

  1. Utwórz HandlerThread

  2. Call start() on HandlerThread

  3. Utwórz Handler pobierając Looper z HanlerThread

  4. Osadzenie kodu związanego z operacjami sieciowymi w obiekcie Runnable

  5. Zgłoś Runnable zadanie do Handler

Przykładowy fragment kodu, który Adres 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);

Zalety stosowania tego podejścia:

  1. Tworzenie nowego Thread/AsyncTask dla każda operacja sieciowa jest kosztowna. Thread/AsyncTask zostanie zniszczony i ponownie utworzony dla następnych operacji sieciowych. Ale przy podejściu Handler i HandlerThread, można przesyłać wiele operacji sieciowych (jako zadania uruchamialne) do pojedynczego HandlerThread za pomocą Handler.
 11
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-05 04:41:03

Chociaż powyżej jest ogromna pula rozwiązań, nikt nie wspomniał com.koushikdutta.ion: https://github.com/koush/ion

Jest również asynchroniczny i bardzo prosty w użyciu:

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
    }
});
 10
Author: msysmilu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-17 10:31:31

Jest jeszcze jeden bardzo wygodny sposób rozwiązania tego problemu-użyj możliwości współbieżności rxJava. Możesz wykonać dowolne zadanie w tle i opublikować wyniki do głównego wątku w bardzo wygodny sposób, więc wyniki te zostaną przekazane do łańcucha przetwarzania.

Pierwszą zweryfikowaną odpowiedzią jest użycie AsynTask. Tak, jest to rozwiązanie, ale obecnie jest przestarzałe, ponieważ wokół są nowe narzędzia.

String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}

Metoda getUrl podaje adres URL i zostanie wykonana na głównym wątku.

MakeCallParseResponse(..)- czy faktycznie działa

ProcessResponse(..)- będzie obsługiwać wynik na głównym wątku.

Kod wykonania asynchronicznego będzie wyglądał następująco:

rx.Observable.defer(new Func0<rx.Observable<String>>() {
    @Override
    public rx.Observable<String> call() {
        return rx.Observable.just(getUrl());
    }
})
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .map(new Func1<String, Object>() {
        @Override
        public Object call(final String s) {
            return makeCallParseResponse(s);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
             processResponse(o);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            // Process error here, it will be posted on
            // the main thread
        }
    });

W porównaniu do AsyncTask, ta metoda pozwala na przełączanie harmonogramów dowolną liczbę razy (powiedzmy, pobieranie danych z jednego harmonogramu i przetwarzanie tych danych na innym (powiedzmy, Scheduler.obliczenie ()). Możesz również zdefiniować własne harmonogramy.

Aby korzystać z tej biblioteki, Dołącz następujące linie do swojego kompilatora.plik gradle:

   compile 'io.reactivex:rxjava:1.1.5'
   compile 'io.reactivex:rxandroid:1.2.0'

Ostatnia zależność zawiera wsparcie dla .mainthread () scheduler.

Istnieje doskonały ebook dla rx-java .

 9
Author: Alex Shutov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-25 09:48:34

RxAndroid to kolejna lepsza alternatywa dla tego problemu i oszczędza nam kłopotów z tworzeniem wątków, a następnie publikowaniem wyników w wątku interfejsu Androida. Musimy tylko określić wątki, na których mają być wykonywane zadania i wszystko jest obsługiwane wewnętrznie.

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. Po określeniu (Schedulers.io()), RxAndroid uruchomi getFavoriteMusicShows() w innym wątku.

  2. Używając AndroidSchedulers.mainThread() chcemy obserwować to, co obserwowalne w wątku UI, tzn. chcemy, aby nasze wywołanie zwrotne onNext() zostało wywołane NA wątek UI

 9
Author: Shinoo Goyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-10 07:52:47

Głównym wątkiem jest wątek interfejsu użytkownika i nie można wykonać operacji w głównym wątku, która może zablokować interakcję użytkownika. Można to rozwiązać na dwa sposoby:

Wymuś wykonanie zadania w głównym wątku w ten sposób

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

Lub Utwórz prosty program obsługi i zaktualizuj główny wątek, jeśli chcesz.

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

I aby zatrzymać użycie wątku:

newHandler.removeCallbacks(runnable);

Aby uzyskać więcej informacji, sprawdź to: bezbolesne gwintowanie

 9
Author: Sharath kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-21 07:08:25

To działa. Tylko uprościłem odpowiedź Dr. Luiji ' ego.

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
 8
Author: Kacy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-13 23:10:17