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?
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"/>
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
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();
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.
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:
- 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
- utilisant un
Service
ouIntentService
à la place, peut-être avec unPendingIntent
pour retourner le résultat par la méthodeonActivityResult
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 équivalentService
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 unActivity
, 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 actifService
. - si vous utilisez votre propre version
IntentService
(comme celui que j'ai relié ci-dessus) vous pouvez contrôler le niveau de concurrence via leExecutor
.
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 .
- Ne pas utiliser strictMode (uniquement en mode debug)
- ne pas modifier la version SDK
- 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
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"/>
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
.
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();
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
}
}
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.
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.
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.
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.)
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
}
});
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"/>
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.)
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.
}
});
**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();
}
});
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:
- vous devez créer un nouveau fil
- Ou utiliser AsyncTask classe
:
mettez toutes vos œuvres à l'intérieur
-
run()
méthode du nouveau fil - 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?
- tout en utilisant AsyncTask, mettre à jour la vue de
onPostExecute()
méthode - Ou appel
runOnUiThread()
méthode et de mettre à jour la vue à l'intérieur de larun()
la méthode.
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 /
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
}
});
ç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();
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.
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.
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);
}
});
-
en spécifiant
(Schedulers.io())
, RxAndroid lanceragetFavoriteMusicShows()
sur un fil différent. -
en utilisant
AndroidSchedulers.mainThread()
nous voulons observer cette Observable sur le thread UI, i.e. nous voulons que notre callbackonNext()
soit appelé sur le thread UI
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:
-
créer
HandlerThread
-
Appel
start()
surHandlerThread
-
créer
Handler
en obtenantLooper
deHanlerThread
-
incorporez votre code D'exploitation de réseau dans
Runnable
objet -
Soumettre
Runnable
tâcheHandler
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:
- la création de nouveaux
Thread/AsyncTask
pour chaque exploitation du réseau est coûteuse. LeThread/AsyncTask
sera détruit et recréé pour les prochaines opérations réseau. Mais avecHandler
etHandlerThread
approche, vous pouvez soumettre de nombreuses opérations réseau (en tant que tâches exécutables) à simpleHandlerThread
en utilisantHandler
.
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. :)
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 .