¿Cómo puedo arreglar 'android.os.NetworkOnMainThreadException'?

Recibí 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?

preguntado el 14 de junio de 11 a las 09:06

Lee esta publicación en el blog en NetworkOnMainThreadException para obtener más información. Explica por qué ocurre esto en Android 3.0 y superior. -

Para estar en el camino del rito, primero lea sobre las solicitudes de red en Android y luego recomendaría estudiar "Volley". -

Hay muchas bibliotecas alternativas que resuelven este problema. Muchos se enumeran al final de esta página. Si tienes más, te los llevamos :) -

Necesita ejecutar actividades de Internet en un hilo separado del hilo principal (UI) -

"Debido a un error en versiones anteriores de Android, el sistema no marcó la escritura en un socket TCP en el hilo principal como una violación del modo estricto. Android 7.0 corrige este error. Las aplicaciones que exhiben este comportamiento ahora lanzan un android.os. NetworkOnMainThreadException ". - ¡Así que algunos de nosotros no hemos llegado a esto hasta hace poco! desarrollador.android.com/about/versions/nougat/… -

30 Respuestas

NOTA: AsyncTask quedó obsoleto en el nivel de API 30.
AsyncTask | Desarrolladores de Android

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

Cómo ejecutar la tarea:

In MainActivity.java archivo, puede agregar esta línea dentro de su oncreate() Método

new RetrieveFeedTask().execute(urlToRssFeed);

No olvide agregar esto a AndroidManifest.xml archivo:

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

respondido 16 mar '21, 20:03

Entonces, esta ejecución de operaciones de red en el hilo principal solo es problemática en Android, no en el código estándar de Java (código escrito en Java pero no para la aplicación de Android). - y_159

Entonces, esta ejecución de operaciones de red en el hilo principal solo es problemática en Android, no en el código estándar de Java (código escrito en Java pero no para la aplicación de Android). - y_159

Casi siempre debe ejecutar operaciones de red en un hilo o como una tarea asincrónica.

Pero is 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

Añada este permiso en el Android manifiesto.xml archivo:

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

Consecuencias:

Su aplicación (en áreas de conexión a Internet irregular) dejará de responder y se bloqueará, el usuario percibe lentitud y tiene que hacer una eliminación forzada, y corre el riesgo de que el administrador de actividades elimine 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 programación para diseñar con capacidad de respuesta: NetworkOnMainThreadException | Desarrolladores de Android

Respondido 22 Jul 21, 11:07

Vaya, gracias por esa explicación que ahora entiendo. Vi una aplicación y había implementado ThreadPolicy en sus clases de Java. Estaba un poco confundido sobre lo que estaba haciendo. Cuando la red estaba baja, estaba viendo la consecuencia de la que estás hablando. - MoisésK

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

Respondido 05 Oct 16, 10:10

¡¡¡Sencillo y brillante !!! - usuario_MGU

¿Cómo le pasarían parámetros a esto? - Haisi

La respuesta aceptada tiene algunas desventajas importantes. No es recomendable utilizar AsyncTask para redes a menos que democracia sepa lo que está haciendo. Algunas de las desventajas incluyen:

  • Las AsyncTask creadas como clases internas no estáticas tienen una referencia implícita al objeto Activity adjunto, su contexto y toda la jerarquía de Vista creada por esa actividad. Esta referencia evita que la actividad se recolecte como basura hasta que se complete el trabajo en segundo plano de 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 en ejecución), o el usuario navega fuera 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 API, AsyncTasks se ejecuta en serie en un único hilo en segundo plano; desde el nivel de API 4 hasta el nivel de API 10, AsyncTasks se ejecuta en un grupo de hasta 128 subprocesos; desde el nivel de API 11 en adelante, AsyncTask se ejecuta en serie en un único hilo en segundo plano (a menos que use el sobrecargado executeOnExecutor método y proporcionar un ejecutor alternativo). El código que funciona bien cuando se ejecuta en serie en ICS puede romperse cuando se ejecuta simultáneamente en Gingerbread, digamos si tiene dependencias inadvertidas en el orden de ejecución.

Si desea evitar fugas de memoria a corto plazo, tener características de ejecución bien definidas en todas las plataformas y tener una base para construir un manejo de red realmente sólido, es posible que desee considerar:

  1. Usando una biblioteca que hace un buen trabajo para usted, hay una buena comparación de las bibliotecas de red en esta preguntao
  2. El uso de un Service or IntentService en cambio, tal vez con un PendingIntent para devolver el resultado a través de la actividad onActivityResult método.

Enfoque IntentService

Desventajas:

  • Más código y complejidad que AsyncTask, aunque no tanto como piensas
  • Pondrá las solicitudes en cola y las ejecutará en un soltero hilo de fondo. Puede controlar esto fácilmente reemplazando IntentService con un equivalente Service implementación, tal vez como esta.
  • Um, no puedo pensar en ningún otro ahora mismo.

Ventajas:

  • Evita el problema de la pérdida de memoria a corto plazo
  • Si su actividad se reinicia mientras las operaciones de red están en curso, aún puede recibir el resultado de la descarga a través de su onActivityResult Método
  • Una plataforma mejor que AsyncTask para crear y reutilizar 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 cambia fuera de la aplicación para atender una llamada telefónica, el sistema puede elimine la aplicación antes de que se complete la carga. Es menos probable para matar una aplicación con un activo Service.
  • Si usa su propia versión concurrente de IntentService (como el que vinculé arriba) puede controlar el nivel de concurrencia a través del Executor.

Resumen de implementación

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

Paso 1: crea un IntentService para realizar la descarga. Puede decirle qué descargar a través de Intent extras, y pásale un PendingIntent utilizar 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 reuse, 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: registre el servicio en el manifiesto:

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

Paso 3: Invoque el servicio desde la Actividad, pasando un objeto PendingResult que el Servicio usará 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 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 proyecto de GitHub que contiene un Android Studio /Gradle el proyecto está disponible aquí.

Respondido 22 Jul 21, 11:07

No puede realizar la red I / O en el hilo de la interfaz de usuario en Panal. Técnicamente, is posible en versiones anteriores de Android, pero es una muy mala idea, ya que hará que su aplicación deje de responder y puede resultar en que el sistema operativo elimine su aplicación por comportarse mal. Deberá ejecutar un proceso en segundo plano o usar AsyncTask para realizar su transacción de red en un hilo en segundo plano.

Hay un articulo sobre Enhebrado indoloro en el sitio para desarrolladores de Android, que es una buena introducción a esto, y le proporcionará una respuesta mucho mejor que la que se puede proporcionar de manera realista aquí.

Respondido 09 Feb 14, 16:02

Hay dos soluciones para este problema.

  1. No utilice una llamada de red en el hilo principal de la interfaz de usuario. Utilice una tarea asíncrona para eso.

  2. Escriba el siguiente código en su archivo MainActivity después setContentView (R.layout.activity_main);:

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

Y la siguiente declaración de importación en su archivo Java.

import android.os.StrictMode;

Respondido 22 Jul 21, 11:07

Seguir su segunda solución es una mala práctica. Async es la forma de hacerlo correctamente. ¡Es como esconder su problema si cambia la política! - richi gonzalez

Realice 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 agregue esto al archivo AndroidManifest.xml:

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

Respondido 22 Jul 21, 12:07

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

Usar Service o AsyncTask

Consulte también la pregunta de desbordamiento de pila:

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

contestado el 23 de mayo de 17 a las 13:05

Quizás valga la pena enfatizar el punto de que si usa un servicio, aún necesitará crear un subproceso separado: las devoluciones de llamada del servicio se ejecutan en el subproceso principal. Un IntentService, por otro lado, ejecuta su método onHandleIntent en un hilo de fondo. - Stevie

¡No debe usar AsyncTask para operaciones de larga duración! Las pautas especifican de 2 a 3 segundos como máximo. - Dias

Desactiva 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: utilizar el AsyncTask de la interfaz del.

Código completo para ambos métodos

Respondido 08 Abr '20, 07:04

Sí, vendría un error ANR. significa que la aplicación no responde en 5 segundos. - muhammad mubashir

Esta es una respuesta realmente mala. No debe cambiar la política del hilo, sino escribir un mejor código: ¡no realice operaciones de red en el hilo principal! - shkschneider

@Sandeep Usted y otros espectadores deberían leer esto también. stackoverflow.com/a/18335031/3470479 - Prakhar1001

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

Así es como se 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();

Respondido el 22 de junio de 16 a las 22:06

Anonymous Runnable NO es la mejor manera, ya que tiene una referencia implícita a la clase adjunta y evita que sea GC ed hasta que se complete el hilo. Además, este hilo se ejecutará con la misma prioridad que el hilo principal / estadounidense, ¡compitiendo con los métodos del ciclo de vida y las velocidades de fotogramas de la interfaz de usuario! - Yousha Aleayoub

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<Void, Void, Void> {

    protected Void doInBackground(Void... arg0) {
        //Your implementation
    }

    protected void onPostExecute(Void result) {
        // TODO: do something with the feed
    }
}

Respondido el 22 de junio de 16 a las 22:06

Esto sucede en Android 3.0 y superior. Desde Android 3.0 y superior, han restringido el uso de operaciones de red (funciones que acceden a Internet) para que no se ejecuten en el hilo principal / hilo de la interfaz de usuario (lo que se genera a partir de sus métodos on create y on resume en la actividad).

Esto es para fomentar el uso de subprocesos separados para operaciones de red. Ver Tarea asíncrona para obtener más detalles sobre cómo realizar las actividades de red de la manera correcta.

Respondido 09 Feb 14, 16:02

Usar Anotaciones de Android es una opción. Le 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.

Respondido 30 Abr '15, 17:04

@Gavriel crea duplicados de todo lo que anota, ya sea un método, actividad, fragmento, singleton, etc., por lo que hay el doble de código y se tarda más en compilarlo. También puede tener algunos problemas debido a errores en la biblioteca. La depuración y la búsqueda de errores se volverían más difíciles. - Oleksiy

El error se debe a la ejecución de operaciones de larga duración en el hilo principal. Puede corregir fácilmente el problema utilizando AsynTarea or Hilo. Puede consultar esta biblioteca AsyncHTTPClientAsyncHTTPClient 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
    }
});

Respondido el 07 de Septiembre de 17 a las 05:09

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

Para simplificar todas estas cosas, Android ofrece varias formas, como AsyncTask, AsyncTaskLoader, CursorLoader or IntentService. Por lo que puede utilizar cualquiera de estos según sus necesidades.

Respondido 09 Feb 14, 16:02

La parte superior respuesta de spektom funciona perfecto

Si está escribiendo el AsyncTask en línea y no extendiéndose como una clase, y además de esto, si hay una necesidad de obtener una respuesta de la AsyncTask, uno puede usar el get() método de la siguiente manera.

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

(De su ejemplo.)

contestado el 23 de mayo de 17 a las 12:05

Esto solo se lanza para aplicaciones dirigidas a Panal SDK o superior. Las aplicaciones destinadas a versiones anteriores del SDK pueden conectarse en red en sus subprocesos de bucle de eventos principales.

¡El error es la advertencia del SDK!

Respondido el 22 de junio de 16 a las 22:06

Para mi fue esto:

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

¡El dispositivo en el que estaba probando mi aplicación era 4.1.2, que es la versión 16 del SDK!

Asegúrese de que la versión de destino sea la misma que la de 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 -> Construir camino -> Android, y debería ser el que esté marcado.

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

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

Respondido el 22 de junio de 16 a las 22:06

Déjame explicarte lo que estás haciendo aquí: NetworkOnMainThreadException es el Guardián que te está diciendo: no dispares a tu propio pie ... tu solución es: volvamos al pasado cuando no había Guardián - ahora puedo disparar a mi pie libremente - Selvin

También tomé este enfoque y no tuve ningún problema. Guardian es demasiado quisquilloso a veces. - FractalBob

Use esto en su actividad

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

                    startActivity(intent);
                }
            }).start();
        }
    });

Respondido el 03 de diciembre de 18 a las 12:12

Solo para deletrear algo explícitamente:

El hilo principal es básicamente el hilo de la interfaz de usuario.

Por lo tanto, decir que no puede realizar operaciones de red en el hilo principal significa que no puede realizar operaciones de red en el hilo de la interfaz de usuario, lo que significa no puede realizar operaciones de red en un *runOnUiThread(new Runnable() { ... }* bloquear dentro de algún otro hilo, tampoco.

(Acabo de tener un largo momento de rascarme la cabeza tratando de averiguar por qué recibía ese error en otro lugar que no sea mi hilo principal. Por eso; este hilo ayudó; y espero que este comentario ayude a alguien más).

Respondido el 24 de junio de 14 a las 22:06

Esta excepción ocurre debido a cualquier tarea pesada realizada en el subproceso principal si esa tarea de ejecución requiere demasiado tiempo.

Para evitar esto, podemos manejarlo usando hilos or ejecutores

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

Respondido el 22 de junio de 16 a las 22:06

Ya hay muchas respuestas excelentes a esta pregunta, pero han aparecido muchas bibliotecas excelentes desde que se publicaron esas respuestas. Esto pretende ser una especie de guía para principiantes.

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

RESTO a través de HTTP

Normalmente JSON, pero puede ser XML o algo más.

Acceso completo a la API

Supongamos que está escribiendo una aplicación que permite a los usuarios realizar un seguimiento de los precios de las acciones, las tasas de interés y los tipos de cambio de divisas. Encuentra una API JSON que se parece a esto:

http://api.example.com/stocks                       // ResponseWrapper<String> object containing a
                                                    // list of strings 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)

Modernización 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 Amazon Ion Java or Volea (sitio web: reequipamiento).

¿Cómo se usa con la API de finanzas?

Declarar impuestos build.gradle

Agregue estas líneas a su módulo nivel build.gradle archivo:

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

Declarar impuestos FinanzasApi.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);
}

Clase Finanzas

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

Clase FinanzasFragmento retazo

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 su API requiere que se envíe una clave de API u otro encabezado, como un token de usuario, etc., Retrofit lo hace fácil (consulte esta asombrosa respuesta a Agregar parámetro de encabezado en la actualización para más detalles).

Acceso único a la API REST

Supongamos que está creando una aplicación de "clima del estado de ánimo" que busca la ubicación del GPS del usuario y verifica la temperatura actual en esa área y les dice el estado de ánimo. Este tipo de aplicación no necesita declarar puntos finales de API; solo necesita poder acceder a un punto final de API.

ion

Esta es una gran biblioteca para este tipo de acceso.

Por favor lee la gran respuesta de msysmilu a ¿Cómo puedo arreglar 'android.os.NetworkOnMainThreadException'?.

Cargar imágenes a través de HTTP

Volea

Volley también se puede usar para API REST, pero debido a la configuración más complicada requerida, prefiero usar reequipamiento desde Square como arriba.

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

Declarar impuestos build.gradle

Agregue esta línea a su módulo nivel build.gradle archivo:

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

Declarar impuestos ImageFetch.java

Volley requiere más configuración que Retrofit. Necesitará crear una clase como esta para configurar un RequestQueue, un ImageLoader y un ImageCache, pero no es tan malo:

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

Declarar impuestos user_view_dialog.xml

Agregue lo siguiente a su archivo XML de diseño para agregar una imagen:

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

Declarar impuestos UserViewDialog.java

Agregue el siguiente código al método onCreate (Fragment, Activity) o al constructor (Dialog):

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

Picasso

Picasso es otra excelente biblioteca de Square. Consulte el sitio web para ver algunos buenos ejemplos.

Respondido 22 Jul 21, 13:07

En palabras simples,

No hacer trabajo de red en el hilo de la interfaz de usuario

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

Solución:

  1. Tienes que crear un nuevo hilo
  2. Or utilizar el Clase AsyncTask

Camino:

Pon todas tus obras dentro

  1. El run() método del nuevo hilo
  2. Or el doInBackground() método de la clase AsyncTask.

Pero:

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

Si no lo hace, obtendrá ViewRootImpl$CalledFromWrongThreadException.

Cómo

  1. Mientras usa AsyncTask, actualice la vista desde el onPostExecute() Método
  2. Or llama a runOnUiThread() método y actualice la vista dentro del run() método.

Respondido 22 Jul 21, 18:07

Puede mover una parte de su código a otro hilo para descargar el main thread y evita conseguir ANR, NetworkOnMainThreadException, IllegalStateExceptionIlegalStateException (p. ej., no puede acceder a la base de datos en el hilo principal ya que potencialmente puede bloquear la interfaz de usuario durante un largo período de tiempo).

Hay algunos enfoques que debe elegir dependiendo de la situación.

Java Hilo o Android Controlador de hilo:

Los subprocesos de Java son de un solo uso y mueren después de ejecutar su método de ejecución.

HandlerThread es una clase útil para iniciar un nuevo hilo que tiene un bucleador.

Tarea asíncrona ( en API nivel 30)

Tarea asíncrona está diseñado para ser una clase de ayuda en torno a Hilo y Manejador y no constituye un marco de subprocesamiento genérico. Lo ideal es que AsyncTasks se utilice para operaciones cortas (unos pocos segundos como máximo). Si necesita mantener los subprocesos en ejecución durante largos períodos de tiempo, se recomienda encarecidamente que utilice las diversas API proporcionadas por el paquete java.util.concurrent, como Ejecutor, ThreadPoolExecutor y FuturoTarea.

Puesto que el principal el hilo monopoliza los componentes de la UI, no es posible acceder a alguna Vista, y es por eso que Handler viene al rescate

[Marco del ejecutor]

ThreadPoolExecutor clase que implementa ExecutorService que brinda un control preciso sobre el grupo de subprocesos (por ejemplo, el tamaño del grupo de núcleos, el tamaño máximo del grupo, el tiempo de mantenimiento activo, etc.)

ScheduledThreadPoolExecutor: una clase que extiende ThreadPoolExecutor. Puede programar tareas después de un retraso determinado o periódicamente.

FuturoTarea

FutureTask realiza un procesamiento asincrónico, sin embargo, si el resultado aún no está listo o el procesamiento no se ha completado, la llamada a get () bloqueará el hilo.

Cargadores de tareas asincrónicas

AsyncTaskLoaders, ya que resuelven muchos problemas inherentes a AsyncTask

IntentService

Esta es la opción de facto para el procesamiento de larga duración en Android, un buen ejemplo sería cargar o descargar archivos grandes. La carga y descarga pueden continuar incluso si el usuario sale de la aplicación y ciertamente no desea bloquear al usuario para que no pueda usar la aplicación mientras se realizan estas tareas.

Programador de trabajos

Efectivamente, debe crear un Servicio y crear un trabajo utilizando JobInfo.Builder que especifique sus criterios sobre cuándo ejecutar el servicio.

RxJava

Biblioteca para componer programas asincrónicos y basados ​​en eventos utilizando secuencias observables.

Corutinas (Kotlin)

La esencia principal de esto es que hace que el código asincrónico se parezca tanto a sincrónico

Leer más aquí, aquí, aquí y aquí.

Respondido 22 Jul 21, 18:07

Nuevo Thread y Tarea asíncrona ya se han explicado las soluciones.

AsyncTask idealmente debería usarse para operaciones cortas. Normal Thread no es preferible para Android.

Eche un vistazo a la solución alternativa usando Controlador de hilo y Manejador

Controlador de hilo

Práctica clase para iniciar un nuevo hilo que tiene un bucleador. El looper se puede utilizar para crear clases de controlador. Tenga en cuenta que start() todavía debe ser llamado.

Manipulador:

Un Handler le permite enviar y procesar objetos Message y Runnable asociados con MessageQueue de un hilo. Cada instancia de Handler está asociada con un solo hilo y la cola de mensajes de ese hilo. Cuando crea un nuevo controlador, está vinculado a la cola de subprocesos / mensajes del subproceso que lo está creando; a partir de ese momento, entregará mensajes y ejecutables a esa cola de mensajes y los ejecutará a medida que salen del mensaje. cola.

Solución:

  1. Crean HandlerThread

  2. Llame al start() on HandlerThread

  3. Crean Handler por conseguir Looper en HanlerThread

  4. Inserte su código relacionado con la operación de red en Runnable objeto

  5. Enviar Runnable tarea para Handler

Fragmento de código de muestra, cuya dirección 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);

Ventajas de usar este enfoque:

  1. Creando nuevo Thread/AsyncTask para cada red la operación es costosa. El Thread/AsyncTask se destruirá y se volverá a crear para las próximas operaciones de la red. Pero con Handler y HandlerThread enfoque, puede enviar muchas operaciones de red (como tareas ejecutables) a un solo HandlerThread mediante el uso Handler.

respondido 05 nov., 17:04

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

Es también asincrónico y muy sencillo usar:

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

Respondido 17 Feb 15, 10:02

El hilo principal es el hilo de la interfaz de usuario y no puede realizar una operación en el hilo principal que pueda bloquear la interacción del usuario. Puedes resolver esto de dos formas:

Fuerza para hacer la tarea en el hilo principal como este

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

O cree un controlador simple y actualice el hilo principal si lo desea.

Runnable runnable;
Handler newHandler;

newHandler = new Handler();
runnable = new Runnable() {
    @Override
    public void run() {
         try {
            //update UI
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
};
newHandler.post(runnable);

Y para detener el uso del hilo:

newHandler.removeCallbacks(runnable);

Para obtener más información, consulte esto: Enhebrado indoloro

Respondido el 21 de enero de 18 a las 07:01

RxAndroid es otra alternativa mejor a este problema y nos ahorra las molestias de crear subprocesos y luego publicar los resultados en el subproceso de la interfaz de usuario de Android.

Solo necesitamos especificar los subprocesos en los que se deben ejecutar las tareas y todo se maneja internamente.

Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {

  @Override
  public List<String> call() {
    return mRestClient.getFavoriteMusicShows();
  }

});

mMusicShowSubscription = musicShowsObservable
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Observer<List<String>>() {

    @Override
    public void onCompleted() { }

    @Override
    public void onError(Throwable e) { }

    @Override
    public void onNext(List<String> musicShows) {
        listMusicShows(musicShows);
    }
});
  1. Especificando (Schedulers.io()), RxAndroid se ejecutará getFavoriteMusicShows() en un hilo diferente.

  2. Mediante el uso AndroidSchedulers.mainThread() queremos observar este Observable en el hilo de la interfaz de usuario, es decir, queremos nuestro onNext() devolución de llamada que se llamará en el subproceso de la interfaz de usuario.

Respondido 22 Jul 21, 18:07

Hay otra forma muy conveniente de abordar este problema: utilice RxJava's capacidades de concurrencia. Puede ejecutar cualquier tarea en segundo plano y publicar resultados en el hilo principal de una manera muy conveniente, por lo que estos resultados se entregarán a la cadena de procesamiento.

El primer consejo de respuesta verificada es usar AsynTask. Sí, esta es una solución, pero está obsoleta hoy en día, porque hay nuevas herramientas alrededor.

String getUrl() {
    return "SomeUrl";
}

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

private void processResponse(Object o) {

}

El obtener URL El método proporciona la dirección URL y se ejecutará en el hilo principal.

makeCallParseResponse(..) - hace el trabajo real

processResponse(..) - manejará el resultado en el hilo principal.

El código para la ejecución asincrónica se verá así:

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

En comparación con AsyncTask, este método permite cambiar de programador un número arbitrario de veces (por ejemplo, buscar datos en un programador y procesar esos datos en otro (por ejemplo, Scheduler.computation ()). También puede definir sus propios programadores.

Para utilizar esta biblioteca, incluya las siguientes líneas en su build.gradle archivo:

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

La última dependencia incluye soporte para el programador .mainThread ().

No hay un excelente libro electrónico para RxJava.

Respondido 22 Jul 21, 18:07

Esto funciona. Acabo de hacer La respuesta del doctor Luiji un poco más simple.

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

Respondido 22 Jul 21, 18:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.