java - tutorial - networkonmainthreadexception httpclient android




Comment puis-je réparer android.os.NetworkOnMainThreadException? (20)

J'ai eu une erreur lors de l'exécution de 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 cela montre l'erreur ci-dessous:

android.os.NetworkOnMainThreadException

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



Cela se produit dans Android 3.0 et supérieur. À partir d'Android 3.0 ou ultérieur, ils ont restreint l'utilisation des opérations réseau (fonctions qui accèdent à Internet) dans le thread principal / thread d'interface utilisateur (ce qui est généré par vos méthodes de création et de reprise dans l'activité).

Ceci encourage l'utilisation de threads distincts pour les opérations réseau. Voir AsyncTask pour plus de détails sur la manière d’exécuter correctement les activités du réseau.


Cette exception est due à une tâche lourde effectuée sur le thread principal si cette tâche d'exécution prend trop de temps .

Pour éviter cela, nous pouvons le gérer en utilisant des threads ou des exécutants

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

Cette exception est levée lorsqu'une application tente d'effectuer une opération de mise en réseau sur son thread principal. Exécutez votre code en 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 le fichier MainActivity.java , vous pouvez ajouter cette ligne dans votre méthode oncreate()

new RetrieveFeedTask().execute(urlToRssFeed);

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

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

Faire 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"/>

Il y a déjà beaucoup de bonnes réponses à cette question, mais beaucoup de bonnes bibliothèques ont été publiées depuis leur publication. Ceci est conçu comme une sorte de guide débutant.

Je couvrirai plusieurs cas d'utilisation pour effectuer des opérations sur le réseau et une solution ou deux pour chacun.

ReST sur HTTP

Typiquement Json, peut être XML ou autre chose

Accès complet à l'API

Supposons que vous écriviez une application permettant aux utilisateurs de suivre les cours des actions, les taux d'intérêt et les taux de change actuels. Vous trouvez une API Json qui ressemble à 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)

Retrofit de Square

C'est un excellent choix pour une API avec plusieurs noeuds finaux et vous permet de déclarer les noeuds finaux ReST au lieu de 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?

build.gradle

Ajoutez ces lignes à votre buid.gradle de niveau Module:

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

Extrait de fragment de finances

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 l'envoi d'une clé API ou d'un autre en-tête, tel qu'un jeton d'utilisateur, etc., Retrofit simplifie cette tâche (pour plus de détails, consultez cette réponse: https://.com/a/42899766/1024412 ).

Accès unique à l'API ReST

Supposons que vous construisez une application «météo d'humeur» qui recherche la position GPS des utilisateurs, vérifie la température actuelle dans cette zone et leur indique l'ambiance. Ce type d'application n'a pas besoin de déclarer les points de terminaison de l'API; il doit simplement pouvoir accéder à un point de terminaison d'API.

Ion

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

Veuillez lire l'excellente réponse de msysmilu ( https://.com/a/28559884/1024412 ).

Charger des images via HTTP

Volée

Volley peut également être utilisé pour les API ReST, mais en raison de la configuration plus complexe requise, je préfère utiliser Retrofit from Square comme ci-dessus ( http://square.github.io/retrofit/ )

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

build.gradle

Ajoutez cette ligne à votre buid.gradle de niveau Module:

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

ImageFetch.java

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

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 les éléments suivants à 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

Ajoutez 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. Veuillez consulter le site pour quelques bons exemples: http://square.github.io/picasso/


Juste pour épeler quelque chose de manière explicite:

Le fil principal est essentiellement le fil de l'interface utilisateur.

Dire que vous ne pouvez pas effectuer d'opérations de réseau dans le thread principal signifie que vous ne pouvez pas effectuer d'opérations de réseau dans le thread d'interface utilisateur, ce qui signifie que vous ne pouvez pas effectuer d'opérations de réseau dans un *runOnUiThread(new Runnable() { ... }* un autre thread. , non plus.

(J'ai juste eu un long moment de réflexion en essayant de comprendre pourquoi j'avais cette erreur ailleurs que dans mon fil principal. C'est pourquoi; ce fil a aidé; et j'espère que ce commentaire aidera quelqu'un d'autre.)


L'erreur est due à l'exécution de longues opérations dans le thread principal. Vous pouvez facilement résoudre le problème en utilisant AsynTask ou Thread . Vous pouvez AsyncHTTPClient cette bibliothèque AsyncHTTPClient pour une meilleure gestion.

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

La réponse acceptée comporte des inconvénients importants. Il est déconseillé d'utiliser AsyncTask pour la mise en réseau, sauf si vous savez vraiment ce que vous faites. Certains des inconvénients incluent:

  • Les AsyncTask créées en tant que classes internes non statiques ont une référence implicite à l'objet Activity englobant, à son contexte et à la totalité de la hiérarchie View créée par cette activité. Cette référence empêche la collecte de déchets de l'activité jusqu'à la fin du travail en arrière-plan de la tâche Async. Si la connexion de l'utilisateur est lente et / ou si le téléchargement est volumineux, 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 en cours d'exécution), ou que l'utilisateur navigue loin de l'activité.
  • AsyncTask a différentes caractéristiques d'exécution en fonction de la plate-forme sur laquelle elle s'exécute: avant le niveau 4 de l'API, AsyncTasks s'exécute en série sur un seul thread en arrière-plan; À partir des API de niveau 4 à 10, les AsyncTasks s'exécutent sur un pool de 128 threads au maximum; À partir du niveau 11 de l'API, AsyncTask s'exécute en série sur un seul thread en arrière-plan (sauf si vous utilisez la méthode executeOnExecutor surchargée et fournissez un autre exécuteur). Le code qui fonctionne correctement lorsqu'il est exécuté en série sur ICS peut se rompre lorsqu'il est exécuté simultanément sur Gingerbread, par exemple si vous avez des dépendances par ordre d'exécution.

Si vous souhaitez éviter les fuites de mémoire à court terme, si vous avez des caractéristiques d’exécution bien définies sur toutes les plates-formes et une base permettant de créer une gestion du réseau vraiment robuste, vous voudrez peut-être prendre en compte:

  1. Utiliser une bibliothèque qui fait un bon travail pour vous - il y a une belle comparaison des bibliothèques réseau dans cette question , ou
  2. Utilisez plutôt Service ou IntentService , peut-être avec un PendingIntent pour renvoyer le résultat via la méthode onActivityResult de onActivityResult .

Approche IntentService

Les inconvénients:

  • Plus de code et de complexité AsyncTask , mais pas autant qu'on pourrait le penser
  • Met les demandes en file d'attente et les exécute sur un seul fil d'arrière-plan. Vous pouvez facilement contrôler cela en remplaçant IntentService par une implémentation Service équivalente, peut-être comme celle-ci .
  • Euh, je ne peux pas penser à d'autres maintenant

Sur les côtés:

  • Evite le problème de fuite de mémoire à court terme
  • Si votre activité redémarre alors que les opérations réseau sont en cours, vous pouvez toujours recevoir le résultat du téléchargement via sa méthode onActivityResult
  • Meilleure plate-forme que AsyncTask pour générer et réutiliser un code réseau robuste. Exemple: si vous devez effectuer un téléchargement important, vous pouvez le faire depuis AsyncTask dans une Activity , mais si le contexte de l'utilisateur quitte l'application pour prendre un appel téléphonique, le système peut supprimer l'application avant la fin du téléchargement. Il est moins susceptible de tuer une application avec un Service actif.
  • Si vous utilisez votre propre version concurrente d' IntentService (comme celle que j'ai liée ci-dessus), vous pouvez contrôler le niveau de simultanéité via l' Executor .

Résumé d'implémentation

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

Étape 1: Créez un IntentService pour effectuer le téléchargement. Vous pouvez lui indiquer le contenu à télécharger via l' Intent supplémentaire, et lui transmettre un objet PendingIntent à utiliser pour renvoyer le résultat à l' 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: inscrivez le service dans le manifeste:

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

Étape 3: Appelez le service depuis l'activité en passant un objet PendingResult que le service utilisera pour renvoyer 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érez 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 projet de travail complet Android-Studio / gradle est disponible here .


Les opérations basées sur le 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.

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

Pour moi c'était ça:

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

L'appareil sur lequel je testais mon application était la version 4.1.2, qui correspond à la version 16 du SDK!

Assurez-vous que la version cible est identique à votre bibliothèque cible Android. Si vous ne savez pas quelle est votre bibliothèque cible, cliquez avec le bouton droit de la souris sur votre projet -> Chemin de construction -> Android , ce qui doit être coché.

En outre, comme d'autres l'ont mentionné, incluez les autorisations appropriées pour accéder à Internet:

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

Utiliser Android Annotations est une option. Cela vous permettra d’exécuter simplement n’importe quelle méthode dans un fil d’arrière-plan:

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

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

Notez que, bien qu'il offre des avantages de simplicité et de lisibilité, il présente des inconvénients.


Vous ne devez effectuer aucune tâche fastidieuse sur le thread principal (thread d'interface utilisateur), comme toute opération de réseau, d'E / S de fichier ou de base de données SQLite. Donc, pour ce type d'opération, vous devez créer un thread de travail, mais le problème est que vous ne pouvez pas effectuer directement d'opération liée à l'interface utilisateur à partir de votre thread de travail. Pour cela, vous devez utiliser Handler et transmettre le Message .

Pour simplifier toutes ces choses, Android propose différentes méthodes, telles que AsyncTask , AsyncTaskLoader , CursorLoader ou IntentService . Vous pouvez donc utiliser ces options en fonction de vos besoins.


Vous ne pouvez pas effectuer d' I/O réseau sur le thread d'interface utilisateur sur Honeycomb . Techniquement, cela est possible sur les versions précédentes d’Android, mais c’est une très mauvaise idée, car votre application cessera de répondre, et le système d’exploitation risque de tuer votre application parce qu’elle se comporte mal. Vous devrez exécuter un processus en arrière-plan ou utiliser AsyncTask pour effectuer votre transaction réseau sur un thread en arrière-plan.

Il existe un article sur Pressed Threading sur le site du développeur Android qui constitue une bonne introduction à ce sujet et qui vous fournira une profondeur de réponse bien meilleure que ce qui peut être fourni de manière réaliste ici.


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

AJOUTEZ cette permission dans le fichier android manifest.xml:

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

Conséquences:

Votre application (dans les zones où la connexion Internet est irrégulière) devient insensible et se bloque, l'utilisateur perçoit la lenteur et doit tuer de force, et vous risquez que le responsable de l'activité tue votre application et dis à l'utilisateur que celle-ci s'est arrêtée.

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


AsynTask solutions nouvelles Threadet AsynTask ont déjà été expliquées.

AsyncTaskdevrait idéalement être utilisé pour des opérations courtes. Normal Threadn'est pas préférable pour Android.

HandlerThread autre solution utilisant HandlerThread et Handler

HandlerThread

Classe pratique pour démarrer un nouveau thread qui a une boucle. Le boucleur peut ensuite être utilisé pour créer des classes de gestionnaires. Notez que cela start()doit encore être appelé.

Gestionnaire:

Un gestionnaire vous permet d’envoyer et de traiter les objets Message et Runnable associés au MessageQueue d’un thread. Chaque instance de gestionnaire est associée à un seul thread et à la file de messages de ce thread. Lorsque vous créez un nouveau gestionnaire, il est lié au thread / à la file d'attente de messages du thread qui le crée - à partir de ce moment, il distribuera les messages et les exécutables à cette file d'attente et les exécutera au fur et à mesure qu'ils sortent du message. queue.

Solution:

  1. Créer HandlerThread

  2. Appel start()surHandlerThread

  3. Créer Handleren obtenant LooperdeHanlerThread

  4. Incorporer le code associé à votre opération réseau dans l' Runnableobjet

  5. Soumettre la Runnabletâche àHandler

Extrait de code, quelle 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 d'utiliser cette approche:

  1. Créer de nouvelles Thread/AsyncTaskpour chaque opération de réseau coûte cher. Le Thread/AsyncTasksera détruit et recréé pour les prochaines opérations du réseau. Mais avec Handleret HandlerThreadapproche, vous pouvez soumettre de nombreuses opérations de réseau (comme les tâches exécutables) à simple à HandlerThreadl'aide Handler.

Cela marche. Je viens de simplifier un peu la réponse de Dr.Luiji.

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

Il existe un autre moyen très pratique de résoudre ce problème - utilisez les fonctionnalités de simultanéité de rxJava. Vous pouvez exécuter n'importe quelle tâche en arrière-plan et publier les résultats sur le thread principal de manière très pratique. Ces résultats seront donc transmis à la chaîne de traitement.

Le premier conseil de réponse vérifié consiste à utiliser AsynTask. Oui, c'est une solution, mais elle est obsolète de nos jours, car il existe de nouveaux outils.

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 sera exécutée sur le thread principal.

makeCallParseResponse (..) - effectue un travail réel

processResponse (..) - gérera le résultat sur le thread principal.

Le code pour l'exécution asynchrone ressemblera à ceci:

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

Comparée à AsyncTask, cette méthode permet de changer de planificateur un nombre arbitraire de fois (par exemple, récupérer des données sur un planificateur et traiter ces données sur un autre (par exemple, Scheduler.computation ()). Vous pouvez également définir vos propres planificateurs.

Pour utiliser cette bibliothèque, incluez les lignes suivantes dans votre fichier build.gradle:

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

La dernière dépendance inclut la prise en charge du planificateur .mainThread ().

Il existe un excellent ebook pour rx-java .


Sur Android, les opérations réseau ne peuvent pas être exécutées sur le thread principal. Vous pouvez utiliser Thread, AsyncTask (tâches à exécution courte), Service (tâches à exécution longue) pour effectuer des opérations réseau.


Vous n'êtes pas autorisé à mettre en œuvre des opérations réseau sur le thread d'interface utilisateur sur Android. Vous devrez utiliser la classe AsyncTask pour effectuer des opérations liées au réseau, telles que l'envoi d'une demande d'API, le téléchargement d'image à partir d'une URL, etc. peut remplir l'interface utilisateur avec des données de service Web ou quelque chose comme ça.

Exemple: supposons que vous souhaitiez télécharger une image depuis une URL: https://www.samplewebsite.com/sampleimage.jpg

Solution utilisant AsyncTask: are 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);
        }


    }
}

Remarque: N'oubliez pas d'ajouter l'autorisation Internet dans le fichier manifeste Android. Cela fonctionnera comme un charme. :)





thread-exceptions