Comment puis-je corriger android.OS.NetworkOnMainThreadException?

j'ai eu une erreur en exécutant mon projet Android pour 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();

et il montre l'erreur suivante:

android.os.NetworkOnMainThreadException

Comment puis-je résoudre ce problème?

2037
demandé sur Ali Esa Assadi 2011-06-14 16:02:00

30 réponses

cette exception est lancée lorsqu'une application tente d'effectuer une opération de réseau sur son fil principal. Exécutez votre code 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
    }
}

Comment exécuter la tâche:

Dans MainActivity.java fichier, vous pouvez ajouter cette ligne dans votre oncreate() méthode

new RetrieveFeedTask().execute(urlToRssFeed);

n'oubliez pas d'ajouter ceci au AndroidManifest.xml fichier:

<uses-permission android:name="android.permission.INTERNET"/>
2281
répondu spektom 2017-11-28 11:57:55

vous devez presque toujours exécuter des opérations réseau sur un thread ou en tant que tâche asynchrone.

mais il est possible de supprimer cette restriction et vous Outrepasser le comportement par défaut, si vous êtes prêt à accepter les conséquences.

ajouter:

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

StrictMode.setThreadPolicy(policy); 

dans votre classe,

et

ajouter cette autorisation dans android manifester.fichier xml:

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

conséquences:

votre application va (dans les zones de connexion Internet flou) devenir insensible et verrouiller, l'utilisateur perçoit la lenteur et doit faire un kill force, et vous risquez le gestionnaire d'activité tuer votre application et de dire à l'utilisateur que l'application a cessé.

Android a quelques bons conseils sur les bonnes pratiques de programmation à concevoir pour la réactivité: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

580
répondu user1169115 2018-02-11 14:18:49

j'ai résolu ce problème en utilisant un nouveau Thread .

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
364
répondu Dr.Luiji 2016-10-05 09:42:24

Vous ne pouvez pas effectuer réseau I/O sur le thread d'INTERFACE utilisateur sur Nid d'abeille . Techniquement, il est possible sur les versions précédentes D'Android, mais c'est une très mauvaise idée car il va provoquer votre application à arrêter de répondre, et peut entraîner dans le système d'exploitation tuer votre application pour être mal comportée. Vous aurez besoin d'exécuter un processus d'arrière-plan ou D'utiliser AsyncTask pour effectuer votre transaction réseau sur un thread d'arrière-plan.

Il ya un article sur fil indolore sur le site développeur Android qui est une bonne introduction à ce, et il vous fournira une bien meilleure profondeur d'une réponse que peut être fourni de façon réaliste ici.

129
répondu Mark Allison 2014-02-09 16:25:22

la réponse acceptée comporte des aspects négatifs importants. Il n'est pas conseillé D'utiliser AsyncTask pour la mise en réseau à moins que vous vraiment savez ce que vous faites. Quelques-uns des côtés négatifs comprennent:

  • AsyncTask est créée comme non-statique à l'intérieur des classes ont une référence implicite à l'encadrement de l'Activité de l'objet, de son contexte, et la Vue d'ensemble de la hiérarchie créée par cette activité. Cette référence empêche l'Activité de les déchets sont ramassés jusqu'à ce que le travail de fond de L'AsyncTask soit terminé. Si la connexion de l'utilisateur est lente, et/ou si le téléchargement est important, ces fuites de mémoire à court terme peuvent devenir un problème-par exemple si l'orientation change plusieurs fois (et que vous n'annulez pas les tâches d'exécution), ou si l'utilisateur navigue loin de l'activité.
  • AsyncTask possède des caractéristiques d'exécution différentes selon la plate-forme sur laquelle il s'exécute: avant le niveau 4 de L'API, AsyncTask s'exécute en série sur un seul thread d'arrière-plan; du niveau API 4 au niveau API 10, Les AsyncTask s'exécutent sur un pool de jusqu'à 128 threads; à partir du niveau API 11, AsyncTask s'exécute en série sur un seul thread d'arrière-plan (à moins que vous n'utilisiez la méthode executeOnExecutor surchargée et que vous ne fournissiez un exécuteur alternatif). Le Code qui fonctionne bien lorsqu'il est exécuté en série sur ICS peut se casser lorsqu'il est exécuté simultanément sur Gingerbread, par exemple, si vous avez des dépendances d'ordre d'exécution involontaires.

If vous voulez éviter les fuites de mémoire à court terme, avoir des caractéristiques d'exécution bien définies sur toutes les plateformes, et avoir une base pour construire une gestion de réseau vraiment robuste, vous pourriez vouloir considérer:

  1. utiliser une bibliothèque qui fait un bon travail de ce pour vous - Il ya une belle comparaison des libs de réseau dans cette question , ou
  2. utilisant un Service ou IntentService à la place, peut-être avec un PendingIntent pour retourner le résultat par la méthode onActivityResult de L'activité.

IntentService approche

Bas-côtés:

  • plus de code et de complexité que AsyncTask , mais pas autant que vous pourriez le penser
  • va mettre les requêtes en file d'attente et les exécuter sur un fil d'arrière-plan simple . Vous pouvez facilement contrôler cela en remplaçant IntentService par un équivalent Service mise en œuvre, peut-être comme celui-ci .
  • Um, Je ne peux pas penser à d'autres en ce moment en fait

Jusqu'à-côtés:

  • évite le problème de fuite de mémoire à court terme
  • si votre activité redémarre alors que les opérations réseau sont en vol, il peut encore recevoir le résultat du téléchargement via sa méthode onActivityResult 1519290920"
  • meilleure plateforme que AsyncTask pour construire et réutiliser du code réseau robuste. Exemple: si vous avez besoin de faire un téléchargement important, vous pouvez le faire à partir de AsyncTask dans un Activity , mais si le contexte utilisateur-sort de l'application pour prendre un appel téléphonique, le système peut tuer l'application avant la fin du téléchargement. Il est moins probable de tuer une application avec un actif Service .
  • si vous utilisez votre propre version IntentService (comme celui que j'ai relié ci-dessus) vous pouvez contrôler le niveau de concurrence via le Executor .

mise en Œuvre "résumé de la 1519440920"

vous pouvez implémenter un IntentService pour effectuer des téléchargements sur un seul thread d'arrière-plan assez facilement.

Étape 1: Créer un IntentService pour effectuer le téléchargement. Vous pouvez lui dire quoi télécharger via Intent extra, et passer un PendingIntent à utiliser pour retourner le résultat du tirage 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);
        }
    }
}

Étape 2: inscrire la signification dans le manifeste:

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

Étape 3: invoquer le service de l'activité, en passant un objet Pendengresult que le Service utilisera pour retourner le résultat:

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

Étape 4: Gérer le résultat dans 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);
}

un projet GitHub contenant un Android-Studio / Grad le projet est disponible ici .

125
répondu Stevie 2017-05-23 12:34:44
  1. Ne pas utiliser strictMode (uniquement en mode debug)
  2. ne pas modifier la version SDK
  3. ne pas utiliser de filetage séparé

Use Service ou AsyncTask

Voir aussi Débordement de Pile question:

android.OS.NetworkOnMainThreadException envoyant un e-mail de Android

61
répondu venergiac 2017-05-23 12:26:38

les actions du réseau sur un autre thread

Par Exemple:

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

et ajoutez ceci à AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
53
répondu henry4343 2016-09-13 19:49:55

vous désactivez le mode strict en utilisant le code suivant:

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

ceci n'est pas recommandé : utilisez l'interface AsyncTask .

code complet pour les deux méthodes

48
répondu Sandeep 2015-08-20 09:04:29
Les opérations réseau

ne peuvent pas être exécutées sur le thread principal. Vous devez exécuter toutes les tâches réseau sur un thread enfant ou implémenter AsyncTask.

C'est ainsi que vous exécutez une tâche dans un thread enfant:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
40
répondu Dhruv Jindal 2016-06-22 21:08:38

mettez votre code à l'intérieur:

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

ou:

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
    }
}
39
répondu Vaishali Sutariya 2016-06-22 21:13:15

utilisant Annotations Android est une option. Il vous permettra simplement d'exécuter n'importe quelle méthode dans un thread de fond:

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

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

noter que bien qu'il offre des avantages de simplicité et de lisibilité, il a ses inconvénients.

37
répondu Oleksiy 2015-04-30 16:46:11

cela se produit dans Android 3.0 et au-dessus. De Android 3.0 et au-dessus, ils ont restreint l'utilisation des opérations réseau (fonctions qui accèdent à Internet) d'exécuter dans le thread principal/UI thread (ce qui se produit à partir de votre sur Créer et sur les méthodes de reprise dans l'activité).

il s'agit d'encourager l'utilisation de threads séparés pour les opérations réseau. Voir AsyncTask pour plus de détails sur la façon d'effectuer les activités de réseau de la bonne façon.

36
répondu raihan ahmed 2014-02-09 16:27:30

vous ne devez pas faire de tâche fastidieuse sur le thread principal (UI thread), comme n'importe quelle opération de réseau, I/O de dossier, ou des opérations de base de données SQLite. Donc pour ce genre d'opération, vous devriez créer un thread de travailleur, mais le problème est que vous ne pouvez pas effectuer directement n'importe quelle opération liée à L'UI à partir de votre thread de travailleur. Pour cela, vous devez utiliser Handler et passer le Message .

pour simplifier toutes ces choses, Android fournit divers moyens, comme AsyncTask , AsyncTaskLoader , CursorLoader ou IntentService . De sorte que vous pouvez les utiliser en fonction de vos besoins.

32
répondu Kapil Vats 2014-02-09 16:29:41

haut réponse de spektom fonctionne parfaitement.

si vous écrivez le AsyncTask en ligne et ne pas étendre comme une classe, et en plus de cela, s'il ya un besoin d'obtenir une réponse sur le AsyncTask , on peut utiliser la méthode get() comme ci-dessous.

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

(D'après son exemple.)

31
répondu sivag1 2017-05-23 11:47:29

l'erreur est due à l'exécution d'opérations de longue durée dans le thread principal,vous pouvez facilement corriger le problème en utilisant AsynTask ou Thread . Vous pouvez consulter cette bibliothèque AsyncHTTPClient pour une meilleure manipulation.

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
    }
});
31
répondu Ashwin S Ashok 2017-09-07 04:53:07

ceci n'est lancé que pour les applications ciblant le Honeycomb SDK ou supérieur. Les Applications ciblant des versions SDK antérieures sont autorisées à faire du réseautage sur leurs fils de boucle d'événements principaux.

l'erreur est L'avertissement SDK!

25
répondu perry 2016-06-22 21:09:34

pour moi c'était ceci:

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

le périphérique sur lequel je testais mon application était 4.1.2 qui est SDK Version 16!

assurez-vous que la version cible est la même que votre bibliothèque cible Android. Si vous n'êtes pas sûr de ce que votre bibliothèque cible est, droit cliquez sur votre projet -> Build Path -> Android , et il devrait être celui qui est coché.

aussi, comme d'autres ont mentionné, inclure les permissions correctes pour accéder à L'Internet:

<uses-permission android:name="android.permission.INTERNET"/>
21
répondu rharvey 2016-06-22 21:07:28

juste pour épeler quelque chose explicitement:

le fil principal est essentiellement le fil UI.

donc dire que vous ne pouvez pas faire des opérations de réseau dans le thread principal signifie que vous ne pouvez pas faire des opérations de réseau dans le thread UI, ce qui signifie vous ne pouvez pas faire des opérations de réseau dans un *runOnUiThread(new Runnable() { ... }* bloc à l'intérieur d'un autre thread, soit.

(je viens d'avoir un long moment à gratter la tête en essayant de comprendre pourquoi j'avais cette erreur ailleurs que dans mon fil principal. C'était pourquoi; ce fil a aidé; et espérons que ce commentaire aidera quelqu'un d'autre.)

19
répondu Novak 2014-06-24 21:32:53

cette exception est due à toute tâche lourde effectuée sur le thread principal si cette tâche prend trop de temps .

pour éviter cela, nous pouvons le manipuler en utilisant threads ou executers

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
17
répondu amardeep 2016-06-22 21:12:36
    **Use like this in Your Activity**

    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 inten=new Intent(getApplicationContext(),ComposeMail.class);
            //intent.putParcelableArrayListExtra("valuesList", value);

            startActivity(inten);



                }
            }).start();
        }
    });
13
répondu dhiraj kakran 2014-03-01 13:43:59

en termes simples,

DO NOT DO NETWORK WORK IN THE UI THREAD

par exemple, si vous faites une requête HTTP, c'est une action réseau.

Solution:

  1. vous devez créer un nouveau fil
  2. Ou utiliser AsyncTask classe

:

mettez toutes vos œuvres à l'intérieur

  1. run() méthode du nouveau fil
  2. Ou doInBackground() méthode de la classe AsyncTask.

mais:

lorsque vous obtenez quelque chose de la réponse réseau et que vous voulez l'afficher sur votre vue (comme afficher le message de réponse dans TextView), vous devez retourner au fil UI .

Si vous ne le faites pas, vous aurez ViewRootImpl$CalledFromWrongThreadException .

Comment faire?

  1. tout en utilisant AsyncTask, mettre à jour la vue de onPostExecute() méthode
  2. Ou appel runOnUiThread() méthode et de mettre à jour la vue à l'intérieur de la run() la méthode.
12
répondu Nabin 2017-05-23 12:10:45

il y a déjà beaucoup de bonnes réponses à cette question, mais beaucoup de bonnes bibliothèques sont sorties depuis que ces réponses ont été postées. C'est une sorte de guide pour débutants.

je vais couvrir plusieurs cas d'utilisation pour effectuer les opérations de réseau et un solution ou deux pour chaque.

repos sur HTTP

typiquement Json, peut être XML ou autre chose

Full API Access

disons que vous écrivez une application qui permet aux utilisateurs de suivre les cours des actions, les taux d'intérêt et les taux de change. Vous trouvez une API Json qui ressemble à quelque chose comme ceci:

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)

Rénovation de la Place

c'est un excellent choix pour une API avec plusieurs endpoints et vous permet de déclarer les endpoints ReST au lieu d'avoir à les coder individuellement comme avec d'autres bibliothèques comme ion ou Volley. (site web: http://square.github.io/retrofit / )

comment l'utilisez-vous avec l'API finances?

"1519340920 de construire".Grad

ajoutez ces lignes à votre buid de niveau Module.Grad le:

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 extrait de

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
    }
}

si votre API nécessite une clé API ou un autre en-tête comme un jeton utilisateur, etc. pour être envoyé, Retrofit rend cela facile (voir cette réponse géniale pour plus de détails: https://stackoverflow.com/a/42899766/1024412 ).

One off ReST API access

disons que vous construisez un application "mood weather" qui recherche la position GPS des utilisateurs et vérifie la température actuelle dans cette zone et leur dit l'Humeur. Ce type d'application n'a pas besoin de déclarer les paramètres de L'API; il lui suffit d'accéder à un paramètre de l'API.

Ion

C'est une grande bibliothèque pour ce type d'accès.

s'il vous Plaît lire msysmilu de la grande réponse ( https://stackoverflow.com/a/28559884/1024412 )

Load images via HTTP

Volley

Volley peut également être utilisé pour les APIs de repos, mais en raison de la configuration plus complexe requis je préfère utiliser la Modernisation À partir du carré comme ci-dessus ( http://square.github.io/retrofit/ )

disons que vous construisez une application de réseau social et que vous voulez charger des photos de profil d'amis.

"1519340920 de construire".Grad

Ajoutez cette ligne à votre buid de niveau Module.Grad le:

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

ImageFetch.java

Volley nécessite plus de configuration que de rénovation. Vous aurez besoin de créer une classe comme celle-ci pour configurer une RequestQueue, un ImageLoader et un ImageCache, mais ce n'est pas trop mal:

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

ajoutez ce qui suit à votre fichier XML de mise en page pour ajouter une image:

<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

ajouter le code suivant à la méthode onCreate (Fragment, Activity) ou au constructeur (Dialog):

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

Picasso

une autre excellente bibliothèque de Square. S'il vous plaît voir le site pour quelques grands exemples: http://square.github.io/picasso /

11
répondu KG6ZVP 2018-03-17 08:26:37

bien qu'au-dessus il y ait un énorme pool de solutions, personne n'a mentionné com.koushikdutta.ion : https://github.com/koush/ion

c'est aussi asynchrone et très simple à utiliser:

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
    }
});
9
répondu msysmilu 2015-02-17 10:31:31

ça marche. Juste fait Dr Luiji réponse un peu plus simple.

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
6
répondu Kacy 2015-02-13 23:10:17

sur Android, les opérations réseau ne peuvent pas être exécutées sur le thread principal. Vous pouvez utiliser Thread, AsyncTask (short-running tasks), Service (long-running tasks) pour effectuer des opérations réseau.

6
répondu Ponsuyambu Velladurai 2016-06-25 09:32:51

accéder aux ressources du réseau à partir du fil principal (UI) cause cette exception. Utilisez un thread séparé ou un AsyncTask pour accéder à une ressource réseau afin d'éviter ce problème.

6
répondu RevanthKrishnaKumar V. 2016-06-25 09:35:31

RxAndroid est une autre meilleure alternative à ce problème et il nous épargne des tracas de créer des threads et ensuite de poster des résultats sur Android UI thread. Nous avons juste besoin de spécifier les threads sur lesquels les tâches doivent être exécutées et tout est géré en interne.

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. en spécifiant (Schedulers.io()) , RxAndroid lancera getFavoriteMusicShows() sur un fil différent.

  2. en utilisant AndroidSchedulers.mainThread() nous voulons observer cette Observable sur le thread UI, i.e. nous voulons que notre callback onNext() soit appelé sur le thread UI

6
répondu Shinoo Goyal 2017-10-10 07:52:47

Nouveau Thread et AsyncTask des solutions ont déjà été expliquées.

AsyncTask devrait idéalement être utilisé pour les opérations de courte durée. Normal Thread n'est pas préférable pour Android.

Ont un oeil à des solutions de rechange à l'aide de HandlerThread et Gestionnaire

HandlerThread

classe pratique pour démarrer un nouveau fil qui a un looper. Le looper peut alors être utilisé pour créer des classes handler. Notez que start() doit encore être appelé.

Gestionnaire:

un gestionnaire vous permet d'envoyer et de traiter des messages et des objets exécutables associés à la MessageQueue d'un thread. Chaque instance du gestionnaire est associée à un seul thread et que la file d'attente de messages de thread. Lorsque vous créez un nouveau Gestionnaire, il est lié à la file d'attente thread / message du thread qui le crée -- à partir de ce point, il délivrera des messages et des exécutables à cette file d'attente de messages et les exécutera lorsqu'ils sortiront de la file d'attente de messages.

Solution:

  1. créer HandlerThread

  2. Appel start() sur HandlerThread

  3. créer Handler en obtenant Looper de HanlerThread

  4. incorporez votre code D'exploitation de réseau dans Runnable objet

  5. Soumettre Runnable tâche Handler

exemple de code snippet, qui 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);

Avantages de cette approche:

  1. la création de nouveaux Thread/AsyncTask pour chaque exploitation du réseau est coûteuse. Le Thread/AsyncTask sera détruit et recréé pour les prochaines opérations réseau. Mais avec Handler et HandlerThread approche, vous pouvez soumettre de nombreuses opérations réseau (en tant que tâches exécutables) à simple HandlerThread en utilisant Handler .
6
répondu Ravindra babu 2017-11-05 04:41:03

vous n'êtes pas autorisé à mettre en œuvre des opérations réseau sur le thread UI sur Android. Vous devrez utiliser la classe AsyncTask pour effectuer des opérations liées au réseau telles que l'envoi D'une requête API, le téléchargement d'une image à partir d'une URL, etc. et en utilisant les méthodes de rappel D'AsyncTask, vous pouvez obtenir le résultat dans onPostExecute menthod et vous serez dans le thread D'UI et vous pouvez peupler L'UI avec des données du service web ou quelque chose comme ça.

exemple: supposez que vous voulez télécharger l'image d'une URL: https://www.samplewebsite.com/sampleimage.jpg

Solution utilisant AsyncTask: sont, respectivement.

    public class MyDownloader extends AsyncTask<String,Void,Bitmap>
    {
        @Override
        protected void onPreExecute() {
            // Show progress dialog
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //Populate Ui
            super.onPostExecute(bitmap);
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            // Open URL connection read bitmaps and return form here
            return result;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            // Show progress update
            super.onProgressUpdate(values);
        }


    }
}

Note: N'oubliez pas d'ajouter la permission Internet dans le fichier manifeste Android. Il fonctionne comme un charme. :)

5
répondu Krishna 2016-06-25 09:39:03

il y a une autre façon très pratique de s'attaquer à ce problème - utiliser les capacités de concurrence de rxJava. Vous pouvez exécuter n'importe quelle tâche en arrière-plan et afficher les résultats sur le thread principal d'une manière très pratique, de sorte que ces résultats seront transmis à la chaîne de traitement.

le premier avis de réponse vérifiée est D'utiliser AsynTask. Oui, c'est une solution, mais elle est obsolète de nos jours, parce qu'il y a de nouveaux outils autour.

String getUrl() {
    return "SomeUrl";
}

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

private void processResponse(Object o) {

}

la méthode getUrl fournit l'adresse URL, et il sera exécuté sur le thread principal.

makeCallParseResponse(..) - ne travail réel

processResponse(..) - poignée de résultat sur le thread principal.

le code pour l'exécution asynchrone ressemblera à:

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

par rapport à AsyncTask, cette méthode permet de changer les ordonnanceurs un nombre arbitraire de fois (par exemple, récupérer des données sur un ordonnanceur et traiter ces données sur un autre (disons, planificateur.calcul.))( Vous pouvez également définir vos propres ordonnanceurs.

afin d'utiliser cette bibliothèque, incluez les lignes suivantes dans votre Compilation.gradle fichier:

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

La dépendance dernière inclut le support pour les .mainthread () scheduler.

Il y a un excellent ebook pour le rx-java .

5
répondu Alex Shutov 2016-06-25 09:48:34