java - thread - oncancelled asynctask android




Come posso risolvere android.os.NetworkOnMainThreadException? (20)

Ho avuto un errore durante l'esecuzione del mio progetto Android per RssReader.

Codice:

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

E mostra l'errore seguente:

android.os.NetworkOnMainThreadException

Come posso risolvere questo problema?



Ci sono già molte ottime risposte su questa domanda, ma molte delle grandi librerie sono uscite da quando sono state pubblicate queste risposte. Questo è inteso come una sorta di guida per principianti.

Tratterò diversi casi d'uso per l'esecuzione di operazioni di rete e una soluzione o due per ciascuno.

ReST su HTTP

Tipicamente Json, può essere XML o qualcos'altro

Accesso API completo

Diciamo che stai scrivendo un'app che consente agli utenti di tenere traccia dei prezzi delle azioni, dei tassi di interesse e dei tassi di cambio del curriculum. Troverai un'API JSON simile a questa:

http://api.example.com/stocks                       //ResponseWrapper<String> object containing a list of Srings with ticker symbols
http://api.example.com/stocks/$symbol               //Stock object
http://api.example.com/stocks/$symbol/prices        //PriceHistory<Stock> object
http://api.example.com/currencies                   //ResponseWrapper<String> object containing a list of currency abbreviation
http://api.example.com/currencies/$currency         //Currency object
http://api.example.com/currencies/$id1/values/$id2  //PriceHistory<Currency> object comparing the prices of the first currency (id1) to the second (id2)

Retrofit da Square

Questa è una scelta eccellente per un'API con più endpoint e consente di dichiarare gli endpoint ReST invece di doverli codificare individualmente come con altre librerie come ion o Volley. (sito Web: http://square.github.io/retrofit/ )

Come lo usi con l'API delle finanze?

build.gradle

Aggiungi queste righe al livello del tuo modulo 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<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);
    }
}

Finanze Frammento di frammento

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

Se la tua API richiede l'invio di una chiave API o di un'altra intestazione come un token utente, ecc., Retrofit semplifica la procedura (consulta questa fantastica risposta per i dettagli: https://.com/a/42899766/1024412 ).

Un accesso all'API ReST

Supponiamo che tu stia costruendo un'app "meteo meteo" che cerca la posizione GPS dell'utente e controlla la temperatura corrente in quell'area e comunica loro l'umore. Questo tipo di app non ha bisogno di dichiarare endpoint API; deve solo essere in grado di accedere a un endpoint dell'API.

ione

Questa è una grande libreria per questo tipo di accesso.

Si prega di leggere l'ottima risposta di msysmilu ( https://.com/a/28559884/1024412 )

Carica immagini via HTTP

raffica

Volley può anche essere usato per le API di ReST, ma a causa della configurazione più complicata richiesta preferisco usare Retrofit da Square come sopra ( http://square.github.io/retrofit/ )

Supponiamo che tu stia costruendo un'app per social network e desideri caricare le foto del profilo degli amici.

build.gradle

Aggiungi questa linea al tuo livello del modulo buid.gradle:

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

ImageFetch.java

Volley richiede più setup rispetto a Retrofit. Dovrai creare una classe come questa per configurare RequestQueue, ImageLoader e ImageCache, ma non è così male:

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

Aggiungi il seguente al tuo file xml di layout per aggiungere un'immagine:

<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

Aggiungi il seguente codice al metodo onCreate (Fragment, Activity) o al costruttore (Dialog):

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

Picasso

Un'altra eccellente libreria di Square. Si prega di consultare il sito per alcuni grandi esempi: http://square.github.io/picasso/


Effettua le azioni di rete su un altro thread

Per esempio:

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

E aggiungilo a AndroidManifest.xml

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

Ho risolto questo problema utilizzando una nuova Thread .

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

Inserisci il tuo codice all'interno:

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

L'errore è dovuto all'esecuzione di operazioni a esecuzione prolungata nel thread principale. È possibile correggere facilmente il problema utilizzando AsynTask o Thread . È possibile eseguire il checkout di questa libreria AsyncHTTPClient per una migliore gestione.

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 migliore risposta di spektom funziona perfettamente.

Se stai scrivendo AsyncTask linea e non si estende come una classe, e in più, se c'è la necessità di ottenere una risposta da AsyncTask , si può usare il metodo get() come sotto.

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

(Dal suo esempio.)


La risposta accettata ha alcuni lati negativi significativi. Non è consigliabile utilizzare AsyncTask per il networking, a meno che tu non sappia veramente cosa stai facendo. Alcuni dei lati negativi includono:

  • AsyncTask creato come classi interne non statiche ha un riferimento implicito all'oggetto Activity che lo racchiude, al suo contesto e all'intera gerarchia View creata da quell'attività. Questo riferimento impedisce che l'attività venga raccolta tramite garbage collector fino al completamento del lavoro in background di AsyncTask. Se la connessione dell'utente è lenta e / o il download è grande, queste perdite di memoria a breve termine possono diventare un problema, ad esempio se l'orientamento cambia più volte (e non si annullano le attività in esecuzione) o l'utente naviga lontano dall'attività.
  • AsyncTask ha caratteristiche di esecuzione diverse a seconda della piattaforma su cui viene eseguito: prima dell'API di livello 4 AsyncTasks esegue in modo seriale su un singolo thread in background; dal livello API 4 al livello API 10, AsyncTasks esegue su un pool di fino a 128 thread; dal livello API 11 in poi AsyncTask viene eseguito in serie su un singolo thread in background (a meno che non si utilizzi il metodo overload executeOnExecutor e si fornisca un executor alternativo). Il codice che funziona bene quando viene eseguito in serie su ICS può interrompersi se eseguito simultaneamente su Gingerbread, ad esempio se si hanno delle dipendenze di ordine di esecuzione involontarie.

Se si desidera evitare perdite di memoria a breve termine, avere caratteristiche di esecuzione ben definite su tutte le piattaforme e avere una base per costruire una gestione di rete davvero solida, si potrebbe prendere in considerazione:

  1. Usando una libreria che fa un buon lavoro per te - c'è un bel confronto tra le librerie di rete in questa domanda , o
  2. Utilizzare invece un Service o IntentService , magari con un PendingIntent per restituire il risultato tramite il metodo onActivityResult di onActivityResult .

Approccio IntentService

Aspetti negativi:

  • Più codice e complessità di AsyncTask , anche se non tanto quanto si potrebbe pensare
  • Accoderà le richieste ed eseguirle su un singolo thread in background. Puoi facilmente controllarlo sostituendo IntentService con un'implementazione di Service equivalente, forse come questa .
  • Um, non riesco a pensare a nessun altro in questo momento

Up-lati:

  • Evita il problema della perdita di memoria a breve termine
  • Se la tua attività si riavvia mentre le operazioni di rete sono in volo, può comunque ricevere il risultato del download tramite il suo metodo onActivityResult
  • Piattaforma migliore di AsyncTask per creare e riutilizzare un robusto codice di rete. Esempio: se devi eseguire un caricamento importante, puoi farlo da AsyncTask in un'attività, ma se l'utente disattiva l'app per effettuare una telefonata, il sistema potrebbe uccidere l'app prima del completamento dell'upload. È meno probabile che uccida un'applicazione con un Service attivo.
  • Se si utilizza la propria versione concorrente di IntentService (come quella che ho collegato sopra) è possibile controllare il livello di concorrenza tramite l' Executor .

Riepilogo dell'implementazione

È possibile implementare un IntentService per eseguire facilmente i download su un singolo thread in background.

Passaggio 1: creare un IntentService per eseguire il download. Puoi dirgli cosa scaricare tramite extra di Intent e passargli un PendingIntent da utilizzare per restituire il risultato 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);
        }
    }
}

Passaggio 2: registrare il servizio nel manifest:

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

Passaggio 3: Richiamare il servizio dall'attività, passando un oggetto PendingResult che verrà utilizzato dal servizio per restituire il risultato:

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

Passaggio 4: gestire il risultato in 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);
}

Qui è disponibile un progetto github contenente un progetto Android-Studio / gradle funzionante.


Non è possibile eseguire I/O rete sul thread dell'interfaccia utente su Honeycomb . Tecnicamente, è possibile su versioni precedenti di Android, ma è una pessima idea in quanto causerà l'interruzione della risposta della tua app e può comportare il blocco dell'OS della tua app. È necessario eseguire un processo in background o utilizzare AsyncTask per eseguire la transazione di rete su un thread in background.

C'è un articolo su Painless Threading sul sito degli sviluppatori Android che è una buona introduzione a questo, e ti fornirà una profondità di una risposta molto migliore di quella che può essere realisticamente fornita qui.


Non si dovrebbe svolgere alcuna attività dispendiosa in termini di tempo sul thread principale (thread dell'interfaccia utente), come qualsiasi operazione di rete, file I / O o operazioni del database SQLite. Pertanto, per questo tipo di operazione, è necessario creare un thread di lavoro, ma il problema è che non è possibile eseguire direttamente operazioni correlate all'interfaccia utente dal thread di lavoro. Per questo, devi usare Handler e passare il Message .

Per semplificare tutte queste cose, Android offre vari modi, come AsyncTask , AsyncTaskLoader , CursorLoader o IntentService . Quindi puoi usare uno di questi in base alle tue esigenze.


Questa eccezione si verifica a causa di qualsiasi attività pesante eseguita sul thread principale se l'attività in esecuzione impiega troppo tempo .

Per evitare ciò, possiamo gestirlo utilizzando thread o esecutori

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

Questa eccezione viene generata quando un'applicazione tenta di eseguire un'operazione di rete sul thread principale. Esegui il tuo codice in 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
    }
}

Come eseguire l'attività:

Nel file MainActivity.java puoi aggiungere questa linea nel tuo metodo oncreate()

new RetrieveFeedTask().execute(urlToRssFeed);

Non dimenticare di aggiungere questo al file AndroidManifest.xml :

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


Solo per spiegare esplicitamente qualcosa:

Il thread principale è fondamentalmente il thread dell'interfaccia utente.

Quindi affermare che non è possibile eseguire operazioni di rete nel thread principale significa che non è possibile eseguire operazioni di rete nel thread dell'interfaccia utente, il che significa che non è possibile eseguire operazioni di rete in un *runOnUiThread(new Runnable() { ... }* blocco *runOnUiThread(new Runnable() { ... }* all'interno di qualche altro thread , o.

(Ho appena avuto un lungo momento di grattacapo cercando di capire perché stavo ottenendo quell'errore da qualche parte oltre al mio thread principale.Questo era il motivo per cui questo thread mi ha aiutato, e spero che questo commento possa aiutare qualcun altro.)


Dovresti quasi sempre eseguire operazioni di rete su un thread o un'attività asincrona.

Ma è possibile rimuovere questa restrizione e si sostituisce il comportamento predefinito, se si è disposti ad accettare le conseguenze.

Inserisci:

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

StrictMode.setThreadPolicy(policy); 

Nella tua classe,

e

AGGIUNGI questa autorizzazione nel file manifest.xml di Android:

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

conseguenze:

La tua app (in aree di scarsa connessione internet) non risponde e si blocca, l'utente percepisce la lentezza e deve fare un kill forzato, e rischi il gestore delle attività che uccide la tua app e che dice all'utente che l'app si è fermata.

Android ha alcuni buoni consigli su buone pratiche di programmazione per progettare per la reattività: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


C'è un altro modo molto conveniente per affrontare questo problema: usa le capacità di concorrenza di rxJava. È possibile eseguire qualsiasi attività in background e pubblicare i risultati sul thread principale in un modo molto conveniente, quindi questi risultati saranno passati alla catena di elaborazione.

Il primo consiglio di risposta verificata è di usare AsynTask. Sì, questa è una soluzione, ma al giorno d'oggi è obsoleta, perché ci sono nuovi strumenti in giro.

String getUrl() {
    return "SomeUrl";
}

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

private void processResponse(Object o) {

}

Il metodo getUrl fornisce l'indirizzo URL e verrà eseguito sul thread principale.

makeCallParseResponse (..) - funziona correttamente

processResponse (..) - gestirà il risultato sul thread principale.

Il codice per l'esecuzione asincrona sarà simile a:

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

Confrontato con AsyncTask, questo metodo consente di cambiare gli scheduler in un numero arbitrario di volte (ad esempio, recuperare i dati su uno scheduler ed elaborarli su un altro (ad esempio, Scheduler.computation ()). È inoltre possibile definire i propri scheduler.

Per utilizzare questa libreria, includere le seguenti righe nel file build.gradle:

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

L'ultima dipendenza include il supporto per lo schedulatore .mainThread ().

C'è un ebook eccellente per rx-java .


Non è consentito implementare operazioni di rete sul thread dell'interfaccia utente su Android. Dovrai utilizzare la classe AsyncTask per eseguire operazioni relative alla rete come inviare richieste API, scaricare immagini da un URL, ecc. E utilizzare i metodi callback di AsyncTask, puoi ottenere risultati in menthod onPostExecute e sarai nel thread dell'interfaccia utente e tu può popolare l'interfaccia utente con i dati del servizio web o qualcosa del genere.

Esempio: supponiamo di voler scaricare l'immagine da un URL: https://www.samplewebsite.com/sampleimage.jpg

Soluzione utilizzando AsyncTask: sono rispettivamente.

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


    }
}

Nota: non dimenticare di aggiungere l'autorizzazione Internet nel file manifest Android. Funzionerà come un fascino. :)


Nuove Threade AsynTask sono già state spiegate.

AsyncTaskdovrebbe idealmente essere utilizzato per operazioni brevi. Normale Threadnon è preferibile per Android.

HandlerThread un'occhiata alla soluzione alternativa usando HandlerThread e Handler

HandlerThread

Comoda lezione per iniziare un nuovo thread che ha un looper. Il looper può quindi essere utilizzato per creare classi di gestori. Nota che start()deve ancora essere chiamato.

handler:

Un gestore consente di inviare ed elaborare oggetti Message e Runnable associati a MessageQueue di un thread. Ogni istanza di Handler è associata a un singolo thread e alla coda di messaggi di quel thread. Quando crei un nuovo Handler, viene associato alla coda thread / messaggi del thread che lo sta creando, da quel momento in poi invierà messaggi e runnables a quella coda di messaggi e li eseguirà non appena escono dal messaggio coda.

Soluzione:

  1. Creare HandlerThread

  2. Chiamata start()suHandlerThread

  3. Crea Handlerda ottenere LooperdaHanlerThread

  4. Incorpora il codice relativo all'operazione di rete Runnablenell'oggetto

  5. Invia Runnableattività aHandler

Snippet di codice di esempio, quale indirizzo 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);

Pro di usare questo approccio:

  1. La creazione di nuovi Thread/AsyncTaskper ogni operazione di rete è costosa. La Thread/AsyncTasksaranno distrutti e ri-creato per le operazioni di rete successiva. Ma con Handlere HandlerThreadapproccio, è possibile inviare molte operazioni di rete (come attività eseguibili) a singoli HandlerThreadutilizzando Handler.

Sebbene sopra ci sia un enorme pool di soluzioni, nessuno menzionato com.koushikdutta.ion: https://github.com/koush/ion

È anche asincrono e molto semplice da usare:

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

Su Android, le operazioni di rete non possono essere eseguite sul thread principale. È possibile utilizzare Thread, AsyncTask (attività a breve durata), Servizio (attività a esecuzione prolungata) per eseguire operazioni di rete.





thread-exceptions