¿Cómo arreglo la excepción android.os.NetworkOnMainThreadException?

Obtuve un error al ejecutar mi proyecto de Android para RssReader.

Código:

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

Y muestra el siguiente error:

 android.os.NetworkOnMainThreadException 

¿Cómo puedo solucionar este problema?

Esta excepción se produce cuando una aplicación intenta realizar una operación de red en su hilo principal. Ejecute su código en AsyncTask :

 class RetrieveFeedTask extends AsyncTask { 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 } } 

Cómo ejecutar la tarea:

En el archivo MainActivity.java puede agregar esta línea dentro de su método oncreate()

 new RetrieveFeedTask().execute(urlToRssFeed); 

No olvides agregar esto al archivo AndroidManifest.xml :

  

Casi siempre debería ejecutar operaciones de red en un subproceso o como una tarea asincrónica.

Pero es posible eliminar esta restricción y anula el comportamiento predeterminado, si está dispuesto a aceptar las consecuencias.

Añadir:

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

En tu clase,

y

AGREGUE este permiso en el archivo android manifest.xml:

  

Consecuencias:

Su aplicación (en áreas de conexión irregular a Internet) no responde y se bloquea, el usuario percibe lentitud y tiene que matar a la fuerza, y se arriesga a que el administrador de actividades mate su aplicación y le diga al usuario que la aplicación se ha detenido.

Android tiene algunos buenos consejos sobre buenas prácticas de progtwigción para diseñar la capacidad de respuesta: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

Resolví este problema usando un nuevo Thread .

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

No puede realizar E / S de red en la secuencia de UI en Honeycomb . Técnicamente, es posible en versiones anteriores de Android, pero es una muy mala idea ya que hará que tu aplicación deje de responder y puede provocar que el sistema operativo mate tu aplicación por comportarse mal. Tendrá que ejecutar un proceso en segundo plano o usar AsyncTask para realizar su transacción de red en una cadena de fondo.

Hay un artículo sobre Painless Threading en el sitio para desarrolladores de Android, que es una buena introducción a esto, y le proporcionará una respuesta mucho más profunda de la que se puede proporcionar de manera realista aquí.

La respuesta aceptada tiene algunas desventajas significativas. No es aconsejable utilizar AsyncTask para redes a menos que realmente sepa lo que está haciendo. Algunos de los inconvenientes incluyen:

  • AsyncTask’s creadas como clases internas no estáticas tienen una referencia implícita al objeto de actividad circundante, su contexto y toda la jerarquía de vistas creada por esa actividad. Esta referencia impide que la actividad se recolecte como basura hasta que se complete el trabajo en segundo plano de la tarea AsyncTask. Si la conexión del usuario es lenta y / o la descarga es grande, estas pérdidas de memoria a corto plazo pueden convertirse en un problema; por ejemplo, si la orientación cambia varias veces (y no cancela las tareas de ejecución), o si el usuario navega lejos de la actividad.
  • AsyncTask tiene diferentes características de ejecución dependiendo de la plataforma en la que se ejecuta: antes del nivel 4 de la API, AsyncTasks se ejecuta en serie en una única cadena de fondo; desde el nivel 4 de API hasta el nivel 10 de API, AsyncTasks se ejecuta en un grupo de hasta 128 subprocesos; desde el nivel 11 de la API en adelante AsyncTask se ejecuta en serie en una única cadena de fondo (a menos que use el método executeOnExecutor sobrecargado y proporcione un ejecutor alternativo). El código que funciona bien cuando se ejecuta en serie en ICS puede romperse cuando se ejecuta al mismo tiempo en Gingerbread, por ejemplo, si tiene dependencias inadvertidas de orden de ejecución.

Si desea evitar memory leaks a corto plazo, tener características de ejecución bien definidas en todas las plataformas y tener una base para desarrollar un manejo de red realmente robusto, es posible que desee considerar:

  1. Usando una biblioteca que hace un buen trabajo de esto para usted, hay una buena comparación de libs de red en esta pregunta , o
  2. Utilizando un Service o IntentService en IntentService lugar, quizás con un PendingIntent para devolver el resultado a través del método Activity onActivityResult .

El enfoque de IntentService

Down-side:

  • Más código y complejidad que AsyncTask , aunque no tanto como podría pensar
  • Pondrá en cola solicitudes y las ejecutará en una sola cadena de fondo. Puede controlar esto fácilmente al reemplazar IntentService con una implementación de Service equivalente, tal como esta .
  • Um, no puedo pensar en otros ahora mismo en realidad

Aspectos positivos:

  • Evita el problema de fuga de memoria a corto plazo
  • Si su actividad se reinicia mientras las operaciones de la red están en vuelo, aún puede recibir el resultado de la descarga a través de su método onActivityResult
  • Mejor plataforma que AsyncTask para construir y reutilizar un código de red robusto. Ejemplo: si necesita realizar una carga importante, puede hacerlo desde AsyncTask en una Activity , pero si el contexto del usuario se desconecta de la aplicación para realizar una llamada telefónica, el sistema puede cancelar la aplicación antes de que se complete la carga. Es menos probable matar una aplicación con un Service activo.
  • Si usa su propia versión concurrente de IntentService (como la que he vinculado anteriormente) puede controlar el nivel de concurrencia a través del Executor .

Resumen de implementación

Puede implementar un IntentService para realizar descargas en un único hilo de fondo con bastante facilidad.

Paso 1: IntentService un IntentService para realizar la descarga. Puedes decirle qué descargar a través de Intent extra, y pasarle un PendingIntent para usar para devolver el resultado a la 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); } } } 

Paso 2: registrar el servicio en el manifiesto:

  

Paso 3: Invoque el servicio de la Actividad, pasando un objeto PendingResult que el Servicio utilizará para devolver el resultado:

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

Paso 4: maneja el resultado en el resultado de actividad:

 @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 proyecto github que contiene un proyecto completo de Android-Studio / gradle está disponible aquí .

  1. No use strictMode (solo en modo de depuración)
  2. No cambie la versión de SDK
  3. No use un hilo separado

Use Service o AsyncTask

Véase también Pregunta de desbordamiento de stack:

android.os.NetworkOnMainThreadException enviando un correo electrónico desde Android

Haga las acciones de red en otro hilo

Por ejemplo:

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

Y agrégalo a AndroidManifest.xml

  

Deshabilita el modo estricto usando el siguiente código:

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

Esto no es recomendable : use la interfaz AsyncTask .

Código completo para ambos métodos

Las operaciones basadas en red no se pueden ejecutar en el hilo principal. Necesita ejecutar todas las tareas basadas en red en un subproceso secundario o implementar AsyncTask.

Así es como ejecuta una tarea en un hilo secundario:

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

Pon tu código dentro:

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

O:

 class DemoTask extends AsyncTask { protected Void doInBackground(Void... arg0) { //Your implementation } protected void onPostExecute(Void result) { // TODO: do something with the feed } } 

Usar anotaciones de Android es una opción. Te permitirá simplemente ejecutar cualquier método en un hilo de fondo:

 // normal method private void normal() { doSomething(); // do something in background } @Background protected void doSomething() // run your networking code here } 

Tenga en cuenta que, aunque proporciona beneficios de simplicidad y legibilidad, tiene sus desventajas.

Esto sucede en Android 3.0 y superior. Desde Android 3.0 y versiones posteriores, han restringido el uso de operaciones de red (funciones que acceden a Internet) para ejecutar en el hilo principal / subproceso de interfaz de usuario (lo que genera a partir de sus métodos de creación y reanudación en la actividad).

Esto es para fomentar el uso de hilos separados para las operaciones de red. Consulte AsyncTask para obtener más detalles sobre cómo realizar actividades de red de la manera correcta.

No debe realizar ninguna tarea que requiera mucho tiempo en el hilo principal (hilo de UI), como cualquier operación de red, archivo de E / S o operaciones de base de datos SQLite. Entonces, para este tipo de operación, debe crear un hilo de trabajo, pero el problema es que no puede realizar directamente ninguna operación relacionada con UI desde su hilo de trabajo. Para eso, debes usar Handler y pasar el Message .

Para simplificar todo esto, Android ofrece varias formas, como AsyncTask , AsyncTaskLoader , CursorLoader o IntentService . Entonces puede usar cualquiera de estos de acuerdo a sus requerimientos.

El error se debe a la ejecución de operaciones de larga ejecución en el hilo principal. Puede rectificar fácilmente el problema utilizando AsynTask o Thread . Puede consultar esta biblioteca AsyncHTTPClient para un mejor manejo.

 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 respuesta principal de spektom funciona perfecto.

Si está escribiendo AsyncTask línea y no se extiende como una clase, y además de esto, si hay una necesidad de obtener una respuesta de la AsyncTask , se puede usar el método get() como se muestra a continuación.

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

(De su ejemplo)

Esto solo se aplica a las aplicaciones orientadas al Honeycomb SDK o superior. Las aplicaciones que se dirigen a versiones anteriores de SDK pueden hacer redes en sus hilos de bucle de eventos principales.

¡El error es la advertencia del SDK!

Para mí fue esto:

  

El dispositivo en el que estaba probando mi aplicación era 4.1.2, que es la versión 16 de SDK.

Asegúrese de que la versión de destino sea la misma que su biblioteca de destino de Android. Si no está seguro de cuál es su biblioteca de destino, haga clic con el botón derecho en su Proyecto -> Ruta de comstackción -> Android , y debería ser el que está marcado.

Además, como han mencionado otros, incluya los permisos correctos para acceder a Internet:

  

Solo para deletrear algo explícitamente:

El hilo principal es básicamente el hilo de UI.

Decir que no se pueden hacer operaciones de red en el hilo principal significa que no se pueden hacer operaciones de red en el hilo de UI, lo que significa que no se pueden hacer operaciones de red en un *runOnUiThread(new Runnable() { ... }* dentro de otro hilo , ya sea.

(Acabo de pasarme un largo rato tratando de descubrir por qué estaba cometiendo ese error en algún otro lado que no sea mi hilo principal. Por eso, este hilo ayudó, y espero que este comentario ayude a alguien más).

Esta excepción se produce debido a cualquier tarea pesada realizada en el hilo principal si esa tarea requiere demasiado tiempo .

Para evitar esto, podemos manejarlo usando hilos o ejecuters

 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(); 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 palabras simples,

NO HAGA TRABAJO DE RED EN LA UI DE HILO

Por ejemplo, si realiza una solicitud HTTP, esa es una acción de red.

Solución:

  1. Tienes que crear un nuevo hilo
  2. O usa la clase AsyncTask

Camino:

Pon todas tus obras adentro

  1. Método run() de nuevo hilo
  2. O el método doInBackground() de la clase AsyncTask.

Pero:

Cuando obtiene algo de la respuesta de la red y desea mostrarlo en su vista (como mostrar el mensaje de respuesta en TextView), debe volver al hilo de la interfaz de usuario .

Si no lo haces, obtendrás ViewRootImpl$CalledFromWrongThreadException .

¿Cómo?

  1. Mientras usa AsyncTask, actualice la vista desde el método onPostExecute()
  2. O llame runOnUiThread() método runOnUiThread() y actualice la vista dentro del método run() .

Aunque arriba hay una gran cantidad de soluciones, nadie mencionó com.koushikdutta.ion : https://github.com/koush/ion

También es asincrónico y muy simple de usar:

 Ion.with(context) .load("http://example.com/thing.json") .asJsonObject() .setCallback(new FutureCallback() { @Override public void onCompleted(Exception e, JsonObject result) { // do stuff with the result or error } }); 

Respuesta 2017:

Ya hay muchas respuestas excelentes sobre esta cuestión, pero han salido muchas grandes bibliotecas desde que se publicaron esas respuestas. Esto es como una especie de guía para novatos.

Cubriré varios casos de uso para realizar operaciones de red y una solución o dos para cada uno.

ReST a través de HTTP

Normalmente Json, puede ser XML o algo más

Acceso completo a la API

Digamos que está escribiendo una aplicación que permite a los usuarios rastrear los precios de las acciones, las tasas de interés y las tasas de cambio de la cotización. Encuentra una API de Json que se parece a esto:

 http://api.example.com/stocks //ResponseWrapper 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 object http://api.example.com/currencies //ResponseWrapper object containing a list of currency abbreviation http://api.example.com/currencies/$currency //Currency object http://api.example.com/currencies/$id1/values/$id2 //PriceHistory object comparing the prices of the first currency (id1) to the second (id2) 

Retrofit de Square

Esta es una excelente opción para una API con múltiples puntos finales y le permite declarar los puntos finales ReST en lugar de tener que codificarlos individualmente como con otras bibliotecas como ion o Volley. (sitio web: http://square.github.io/retrofit/ )

¿Cómo lo usas con la API de finanzas?

build.gradle

Agregue estas líneas a su nivel de módulo buid.gradle:

 implementation 'com.squareup.retrofit2:retrofit:2.3.0' //retrofit library, current as of September 21, 2017 implementation 'com.squareup.retrofit2:converter-gson:2.3.0' //gson serialization and deserialization support for retrofit, version must match retrofit version 

FinancesApi.java

 public interface FinancesApi { @GET("stocks") Call> listStocks(); @GET("stocks/{symbol}") Call getStock(@Path("symbol")String tickerSymbol); @GET("stocks/{symbol}/prices") Call> getPriceHistory(@Path("symbol")String tickerSymbol); @GET("currencies") Call> listCurrencies(); @GET("currencies/{symbol}") Call getCurrency(@Path("symbol")String currencySymbol); @GET("currencies/{symbol}/values/{compare_symbol}") Call> getComparativeHistory(@Path("symbol")String currency, @Path("compare_symbol")String currencyToPriceAgainst); } 

FinanzasApiBuilder

 public class FinancesApiBuilder { public static FinancesApi build(String baseUrl){ return new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build() .create(FinancesApi.class); } } 

Fragmento de fragmento de Fragment

 FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior api.getStock("INTC").enqueue(new Callback(){ @Override public void onResponse(Call stockCall, Response stockResponse){ Stock stock = stockCall.body(); //do something with the stock } @Override public void onResponse(Call stockCall, Throwable t){ //something bad happened } } 

Si su API requiere una clave API u otro encabezado como un token de usuario, etc. para enviar, Retrofit lo hace fácil (consulte esta impresionante respuesta para obtener más información: https://stackoverflow.com/a/42899766/1024412 ).

Uno de acceso API ReST

Supongamos que está creando una aplicación de “clima ambiental” que busca la ubicación GPS de los usuarios y verifica la temperatura actual en esa área y les indica el estado de ánimo. Este tipo de aplicación no necesita declarar extremos de API; solo necesita poder acceder a un punto final API.

Ion

Esta es una gran biblioteca para este tipo de acceso.

Por favor, lea la gran respuesta de msysmilu ( https://stackoverflow.com/a/28559884/1024412 )

Cargar imágenes a través de HTTP

Voleo

Volley también se puede usar para las API ReST, pero debido a la configuración más complicada que se requiere, prefiero usar Retrofit from Square como se indicó anteriormente ( http://square.github.io/retrofit/ )

Supongamos que está creando una aplicación de red social y desea cargar imágenes de perfil de amigos.

build.gradle

Agregue esta línea a su nivel de módulo buid.gradle:

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

ImageFetch.java

Volley requiere más configuración que Retrofit. Tendrá que crear una clase como esta para configurar un RequestQueue, un ImageLoader y un ImageCache, pero no está tan 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 cache = new HashMap(); @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

Add the following to your layout xml file to add an image:

  

UserViewDialog.java

Add the following code to the onCreate method (Fragment, Activity) or the constructor (Dialog):

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

Picasso

Another excellent library from Square. Please see the site for some great examples: http://square.github.io/picasso/

RxAndroid is another better alternative to this problem and it saves us from hassles of creating threads and then posting results on Android UI thread. We just need to specify threads on which tasks need to be executed and everything is handled internally.

 Observable> musicShowsObservable = Observable.fromCallable(new Callable>() { @Override public List call() { return mRestClient.getFavoriteMusicShows(); } }); mMusicShowSubscription = musicShowsObservable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(List musicShows){ listMusicShows(musicShows); } }); 
  1. By specifiying (Schedulers.io()) ,RxAndroid will run getFavoriteMusicShows() on a different thread.

  2. By using AndroidSchedulers.mainThread() we want to observe this Observable on the UI thread, ie we want our onNext() callback to be called on the UI thread

New Thread and AsyncTask solutions have been explained already.

AsyncTask should ideally be used for short operations. Normal Thread is not preferable for Android.

Have a look at alternate solution using HandlerThread and Handler

HandlerThread

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

Handler:

Un controlador le permite enviar y procesar mensajes y objetos ejecutables asociados con MessageQueue de un hilo. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

Solución:

  1. Create HandlerThread

  2. Call start() on HandlerThread

  3. Create Handler by getting Looper from HanlerThread

  4. Embed your Network operation related code in Runnable object

  5. Submit Runnable task to Handler

Sample code snippet, which address 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); 

Pros of using this approach:

  1. Creating new Thread/AsyncTask for each network operation is expensive. The Thread/AsyncTask will be destroyed and re-created for next Network operations. But with Handler and HandlerThread approach, you can submit many network operations (as Runnable tasks) to single HandlerThread by using Handler .

Esto funciona. Just made Dr.Luiji’s answer a little simpler.

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

On Android, network operations cannot be run on the main thread. You can use Thread, AsyncTask (short-running tasks), Service (long-running tasks) to do network operations.

Accessing network resources from the main (UI) thread cause this exception. Use a separate thread or AsyncTask for accessing a network resource to avoid this problem.

You are not allowed to implement network operations on the UI thread on Android. You will have to use AsyncTask class to perform network related operations like sending API request, downloading image from a URL, etc. and using callback methods of AsyncTask, you can get you result in onPostExecute menthod and you will be in the UI thread and you can populate UI with data from web service or something like that.

Example: Suppose you want to download image from an URL: http://img.rephp.com/java/sampleimage.jpg

Solution using AsyncTask: are respectively.

  public class MyDownloader extends AsyncTask { @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: Do not forget to add the Internet permission in the Android manifest file. It will work like a charm. 🙂

There is another very convenient way for tackling this issue – use rxJava’s concurrency capabilities. You can execute any task in background and post results to main thread in a very convenient way, so these results will be handed to processing chain.

The first verified answer advice is to use AsynTask. Yes, this is a solution, but it is obsolete nowadays, because there are new tools around.

 String getUrl() { return "SomeUrl"; } private Object makeCallParseResponse(String url) { return null; // } private void processResponse(Object o) { } 

The getUrl method provides the URL address, and it will be executed on the main thread.

makeCallParseResponse(..) – does actual work

processResponse(..) – will handle result on main thread.

The code for asynchronous execution will look like:

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

Compared to AsyncTask, this method allow to switch schedulers an arbitrary number of times (say, fetch data on one scheduler and process those data on another (say, Scheduler.computation()). You can also define you own schedulers.

In order to use this library, include following lines into you build.gradle file:

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

The last dependency includes support for the .mainThread() scheduler.

There is an excellent ebook for rx-java .