J'ai reçu 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 il montre l'erreur ci-dessous:
android.os.NetworkOnMainThreadException
Comment puis-je résoudre ce problème?
java
android
android-networking
networkonmainthread
bejoy george
la source
la source
Réponses:
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 dans
AsyncTask
:Comment exécuter la tâche:
Dans le
MainActivity.java
fichier, vous pouvez ajouter cette ligne dans votreoncreate()
méthodeN'oubliez pas d'ajouter ceci au
AndroidManifest.xml
fichier:la source
AsyncTask
et prend en charge un changement de configuration.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 remplacez le comportement par défaut, si vous êtes prêt à accepter les conséquences.
Ajouter:
Dans votre classe,
et
AJOUTER cette autorisation dans le fichier android manifest.xml:
Conséquences:
Votre application (dans les zones de connexion Internet inégale) ne répond plus et se bloque, l'utilisateur perçoit la lenteur et doit effectuer une mise à mort forcée, et vous risquez que le gestionnaire d'activité tue votre application et informe l'utilisateur que l'application est arrêtée.
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
la source
doInBackground
déclaration, 2 crochets de fermeture et un appel àexecute()
). D'un autre côté, même une seule extraction depuis un site, comme vous le mentionnez, entraîne un retard important dans la réactivité de l'interface utilisateur. Ne sois pas paresseux.J'ai résolu ce problème en utilisant un nouveau
Thread
.la source
La réponse acceptée présente des inconvénients importants. Il n'est pas conseillé d'utiliser AsyncTask pour la mise en réseau à moins que vous ne sachiez vraiment ce que vous faites. Certains des inconvénients comprennent:
executeOnExecutor
méthode surchargée et fournissez un exécuteur alternatif). Le code qui fonctionne correctement lors de l'exécution 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 par défaut d'exécution.Si vous souhaitez éviter les fuites de mémoire à court terme, avoir des caractéristiques d'exécution bien définies sur toutes les plates-formes et disposer d'une base pour créer une gestion de réseau vraiment robuste, vous pouvez envisager:
Service
ou à laIntentService
place, peut-être avec unPendingIntent
pour retourner le résultat via laonActivityResult
méthode de l'activité .Approche IntentService
Inconvénients:
AsyncTask
vous ne le pensez, mais pas autantIntentService
par uneService
implémentation équivalente , peut-être comme celle-ci .À l'envers:
onActivityResult
méthodeAsyncTask
d'unActivity
, mais si l'utilisateur change de contexte 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 actifService
.IntentService
(comme celle que j'ai liée ci-dessus), vous pouvez contrôler le niveau de concurrence via leExecutor
.Résumé de la mise en œuvre
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éez un
IntentService
pour effectuer le téléchargement. Vous pouvez lui dire quoi télécharger via desIntent
extra, et le passerPendingIntent
à utiliser pour retourner le résultat àActivity
:Étape 2: inscrivez le service dans le manifeste:
Étape 3: appelez le service à partir de l'activité, en passant un objet PendingResult que le service utilisera pour renvoyer le résultat:
Étape 4: gérer le résultat dans onActivityResult:
Un projet Github contenant un projet Android-Studio / Gradle complet est disponible ici .
la source
IllustrativeRSS
? Et si vous ne travaillez pas avec des trucs RSS?AsyncTask
. L'erreur était destinée à empêcher les développeurs de ralentir l'interface utilisateur, pas nécessairement les inciter à risquer la sécurité avec un tas d'intentions / services.Vous ne pouvez pas effectuer d' E / S réseau sur le thread d'interface utilisateur sur Honeycomb . Techniquement, cela est possible sur les versions antérieures d'Android, mais c'est une très mauvaise idée car cela entraînera la cessation de votre application et le système d'exploitation peut tuer votre application pour son mauvais comportement. Vous devrez exécuter un processus d'arrière-plan ou utiliser AsyncTask pour effectuer votre transaction réseau sur un thread d'arrière-plan.
Il y a un article sur le filetage indolore sur le site des développeurs Android qui est une bonne introduction à cela, et il vous fournira une bien meilleure profondeur de réponse que ce qui peut être réaliste ici.
la source
Utiliser Service ou AsyncTask
Voir aussi la question Stack Overflow:
android.os.NetworkOnMainThreadException envoi d'un e-mail à partir d'Android
la source
Faites les actions du réseau sur un autre thread
Et ajoutez ceci à AndroidManifest.xml
la source
Vous désactivez le mode strict à l'aide du code suivant:
Ce n'est pas recommandé : utilisez l'
AsyncTask
interface.Code complet pour les deux méthodes
la source
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.
Voici comment exécuter une tâche dans un thread enfant:
la source
Mettez votre code à l'intérieur:
Ou:
la source
Cela se produit dans Android 3.0 et supérieur. À partir d'Android 3.0 et versions ultérieures, ils ont restreint l'utilisation des opérations réseau (fonctions qui accèdent à Internet) pour s'exécuter dans le thread principal / thread d'interface utilisateur (ce qui apparaît à partir des méthodes de création et de reprise de 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 correctement les activités réseau.
la source
L'utilisation d' annotations Android est une option. Il vous permettra d'exécuter simplement n'importe quelle méthode dans un thread d'arrière-plan:
Notez que, bien qu'il offre des avantages de simplicité et de lisibilité, il présente ses inconvénients.
la source
L'erreur est due à l'exécution de longues opérations dans le thread principal. Vous pouvez facilement corriger le problème en utilisant AsynTask ou Thread . Vous pouvez extraire cette bibliothèque AsyncHTTPClient pour une meilleure gestion.
la source
Vous ne devez pas effectuer de tâche longue sur le thread principal (thread d'interface utilisateur), comme toute opération réseau, les E / S de fichiers ou les opérations 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 passer leMessage
.Pour simplifier toutes ces choses, Android fournit diverses manières, comme
AsyncTask
,AsyncTaskLoader
,CursorLoader
ouIntentService
. Vous pouvez donc utiliser n'importe lequel de ces éléments selon vos besoins.la source
La meilleure réponse de spektom fonctionne parfaitement.
Si vous écrivez l'
AsyncTask
inline et ne l'étendez pas en tant que classe, et en plus de cela, s'il est nécessaire d'obtenir une réponseAsyncTask
, vous pouvez utiliser laget()
méthode ci-dessous.(D'après son exemple.)
la source
get()
est une mauvaise idée ... cela permet à AsyncTask de se "synchroniser" à nouveauCeci est uniquement lancé pour les applications ciblant le nid d'abeille SDK ou supérieur. Les applications ciblant les versions antérieures du SDK sont autorisées à faire du réseautage sur leurs principaux threads de boucle d'événements.
L'erreur est l'avertissement du SDK!
la source
Pour moi, c'était ça:
L'appareil sur lequel je testais mon application était 4.1.2, qui est la version 16 du SDK!
Assurez-vous que la version cible est la même que votre bibliothèque cible Android. Si vous ne savez pas quelle est votre bibliothèque cible, cliquez avec le bouton droit sur votre projet -> Chemin de génération -> Android , et ce devrait être celui qui est coché.
En outre, comme d'autres l'ont mentionné, incluez les autorisations appropriées pour accéder à Internet:
la source
NetworkOnMainThreadException
est le Guardian qui vous dit: ne tirez pas à votre propre pied ... votre solution est: revenons au passé quand il n'y avait pas de Guardian - maintenant je peux tirer sur mon pied librementUtilisez ceci dans votre activité
la source
Juste pour énoncer explicitement quelque chose:
Le thread principal est essentiellement le thread d'interface utilisateur.
Donc, dire que vous ne pouvez pas faire d'opérations de mise en réseau dans le thread principal signifie que vous ne pouvez pas faire d'opérations de mise en réseau dans le thread d'interface utilisateur, ce qui signifie que vous ne pouvez pas faire d'opérations de mise en réseau dans un
*runOnUiThread(new Runnable() { ... }*
bloc intérieur d'un autre thread.(J'ai juste passé un long moment à me gratter la tête en essayant de comprendre pourquoi j'obtenais 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.)
la source
Cette exception se produit en raison de toute 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écuteurs
la source
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é publiées. Il s'agit d'une sorte de guide pour les débutants.
Je couvrirai plusieurs cas d'utilisation pour effectuer des opérations réseau et une solution ou deux pour chacun.
ReST sur HTTP
Typiquement Json, peut être XML ou autre
Accès complet à l'API
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 en cours. Vous trouvez une API Json qui ressemble à ceci:
Rénovation de Square
C'est un excellent choix pour une API avec plusieurs points de terminaison et vous permet de déclarer les points de terminaison 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?
build.gradle
Ajoutez ces lignes à votre niveau de module buid.gradle:
FinancesApi.java
FinancesApiBuilder
Extrait de fragment
Si votre API nécessite l'envoi d'une clé API ou d'un autre en-tête comme un jeton d'utilisateur, etc., Retrofit facilite cela (voir cette réponse géniale pour plus de détails: https://stackoverflow.com/a/42899766/1024412 ).
Accès unique à l'API ReST
Imaginons que vous construisiez une application "météo d'humeur" qui recherche la position GPS des utilisateurs et 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 des points de terminaison API; il doit juste être en mesure d'accéder à un point de terminaison API.
Ion
Il s'agit d'une excellente bibliothèque pour ce type d'accès.
Veuillez lire l'excellente réponse de msysmilu ( https://stackoverflow.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 créez une application de réseautage social et que vous souhaitez charger des photos de profil d'amis.
build.gradle
Ajoutez cette ligne à votre niveau de module buid.gradle:
ImageFetch.java
Volley nécessite plus de configuration que Retrofit. Vous devrez créer une classe comme celle-ci pour configurer un RequestQueue, un ImageLoader et un ImageCache, mais ce n'est pas trop mal:
user_view_dialog.xml
Ajoutez ce qui suit à votre fichier xml de mise en page pour ajouter une image:
UserViewDialog.java
Ajoutez le code suivant à la méthode onCreate (Fragment, Activity) ou au constructeur (Dialog):
Picasso
Une autre excellente bibliothèque de Square. Veuillez consulter le site pour de bons exemples: http://square.github.io/picasso/
la source
En termes simples,
NE PAS FAIRE DE TRAVAIL EN RÉSEAU DANS LE FIL D'UI
Par exemple, si vous effectuez une requête HTTP, il s'agit d'une action réseau.
Solution:
Façon:
Mettez toutes vos œuvres à l'intérieur
run()
méthode du nouveau threaddoInBackground()
méthode de la classe AsyncTask.Mais:
Lorsque vous obtenez quelque chose de la réponse du réseau et que vous souhaitez l'afficher sur votre vue (comme afficher le message de réponse dans TextView), vous devez revenir au thread de l'interface utilisateur .
Si vous ne le faites pas, vous obtiendrez
ViewRootImpl$CalledFromWrongThreadException
.Comment?
onPostExecute()
méthoderunOnUiThread()
méthode et mettez à jour la vue à l'intérieur de larun()
méthode.la source
Vous êtes en mesure de déplacer une partie de votre code dans un autre thread pour décharger le
main thread
et éviter d'obtenir ANR , NetworkOnMainThreadException , IllegalStateException (par exemple, impossible d'accéder à la base de données sur le thread principal car il peut potentiellement verrouiller l'interface utilisateur pendant une longue période de temps).Il existe certaines approches que vous devez choisir en fonction de la situation
Thread Java ou Android HandlerThread
AsyncTask
Implémentation du pool de threads ThreadPoolExecutor , ScheduledThreadPoolExecutor ...
FutureTask
AsyncTaskLoaders
IntentService
JobScheduler
RxJava
Coroutines (Kotlin)
En savoir plus ici , ici , ici , ici
la source
Bien qu'au-dessus il y ait un énorme pool de solutions, personne n'a mentionné
com.koushikdutta.ion
: https://github.com/koush/ionIl est également asynchrone et très simple à utiliser:
la source
Nouveau
Thread
et AsyncTask solutions ont déjà été expliquées.AsyncTask
devrait idéalement être utilisé pour de courtes opérations. OrdinaireThread
n'est pas préférable pour Android.Découvrez une solution alternative à l'aide de HandlerThread et Handler
HandlerThread
Gestionnaire:
Solution:
Créer
HandlerThread
appelez
start()
leHandlerThread
Créez
Handler
en obtenantLooper
deHanlerThread
Incorporez votre code lié aux opérations réseau dans l'
Runnable
objetSoumettre la
Runnable
tâche àHandler
Exemple d'extrait de code, qui adresse
NetworkOnMainThreadException
Avantages d'utiliser cette approche:
Thread/AsyncTask
pour chaque opération de réseau coûte cher. LeThread/AsyncTask
sera détruit et recréé pour les prochaines opérations du réseau. Mais avecHandler
etHandlerThread
approche, vous pouvez soumettre de nombreuses opérations réseau (en tant que tâches exécutables) à une seuleHandlerThread
à l'aide deHandler
.la source
Il existe un autre moyen très pratique de résoudre ce problème: utilisez les capacités de concurrence 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, de sorte que ces résultats seront transmis à la chaîne de traitement.
Le premier conseil de réponse vérifié est d'utiliser AsynTask. Oui, c'est une solution, mais elle est obsolète de nos jours, car il y a de nouveaux outils autour.
La méthode getUrl fournit l'adresse URL et elle sera exécutée sur le thread principal.
makeCallParseResponse (..) - fait un travail réel
processResponse (..) - gérera le résultat sur le thread principal.
Le code pour l'exécution asynchrone ressemblera à:
Par rapport à 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.
Afin d'utiliser cette bibliothèque, incluez les lignes suivantes dans votre fichier build.gradle:
La dernière dépendance inclut la prise en charge du planificateur .mainThread ().
Il existe un excellent ebook pour rx-java .
la source
RxAndroid
est une autre meilleure alternative à ce problème et cela nous évite d'avoir à créer des threads et à publier des résultats sur le thread de l'interface utilisateur Android. 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.En spécifiant
(Schedulers.io())
, RxAndroid s'exécuteragetFavoriteMusicShows()
sur un thread différent.En utilisant,
AndroidSchedulers.mainThread()
nous voulons observer cet observable sur le thread d'interface utilisateur, c'est-à-dire que nous voulons que notreonNext()
rappel soit appelé sur le thread d'interface utilisateurla source
Le thread principal est le thread d'interface utilisateur, et vous ne pouvez pas effectuer une opération dans le thread principal qui peut bloquer l'interaction utilisateur. Vous pouvez résoudre ce problème de deux manières:
Forcer à faire la tâche dans le thread principal comme ceci
Ou créez un gestionnaire simple et mettez à jour le thread principal si vous le souhaitez.
Et pour arrêter l'utilisation du fil:
Pour plus d'informations, vérifiez ceci: Filetage indolore
la source
Cela marche. Je viens de rendre la réponse du Dr Luiji un peu plus simple.
la source
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.
la source