Pertanyaan Bagaimana cara memperbaiki android.os.NetworkOnMainThreadException?


Saya mendapat kesalahan saat menjalankan proyek Android saya untuk RssReader.

Kode:

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

Dan itu menunjukkan kesalahan di bawah ini:

android.os.NetworkOnMainThreadException

Bagaimana saya bisa memperbaiki masalah ini?


1969
2018-06-14 12:02


asal


Jawaban:


Pengecualian ini dilemparkan ketika aplikasi mencoba untuk melakukan operasi jaringan pada utas utama. Jalankan kode Anda 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
    }
}

Cara menjalankan tugas:

Di MainActivity.java file Anda dapat menambahkan baris ini dalam Anda oncreate() metode

new RetrieveFeedTask().execute(urlToRssFeed);

Jangan lupa untuk menambahkan ini AndroidManifest.xml mengajukan:

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

2232
2018-06-14 12:15



Anda hampir selalu harus menjalankan operasi jaringan pada utas atau sebagai tugas asynchronous.

Tetapi aku s mungkin untuk menghapus pembatasan ini dan Anda mengesampingkan perilaku default, jika Anda bersedia menerima konsekuensinya.

Menambahkan:

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

StrictMode.setThreadPolicy(policy); 

Di kelas Anda,

dan

TAMBAH izin ini di file manifes.xml android:

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

Konsekuensi:

Aplikasi Anda akan (di area koneksi internet jerawatan) menjadi tidak responsif dan mengunci, pengguna merasakan kelambatan dan harus melakukan pembunuhan paksa, dan Anda berisiko manajer aktivitas yang membunuh aplikasi Anda dan memberi tahu pengguna bahwa aplikasi telah berhenti.

Android memiliki beberapa kiat bagus tentang praktik pemrograman yang baik untuk mendesain agar responsif: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


556
2018-02-15 06:59



Saya memecahkan masalah ini menggunakan yang baru Thread.

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

346
2018-01-21 16:31



Anda tidak dapat melakukan jaringan I / O pada utas UI Sarang madu. Secara teknis, itu aku s mungkin pada versi Android sebelumnya, tetapi itu adalah ide yang sangat buruk karena akan menyebabkan aplikasi Anda berhenti merespons, dan dapat mengakibatkan OS membunuh aplikasi Anda karena berperilaku buruk. Anda harus menjalankan proses latar belakang atau menggunakan AsyncTask untuk melakukan transaksi jaringan Anda pada utas latar belakang.

Ada artikel tentang Threading tanpa rasa sakit di situs pengembang Android yang merupakan pengantar yang bagus untuk ini, dan ini akan memberi Anda kedalaman jawaban yang jauh lebih baik daripada yang dapat disediakan secara realistis di sini.


124
2018-06-14 12:07



Jawaban yang diterima memiliki beberapa sisi bawah yang signifikan. Tidak disarankan untuk menggunakan AsyncTask untuk jaringan kecuali Anda sangat tahu apa yang kamu lakukan. Beberapa sisi bawah meliputi:

  • AsyncTask dibuat sebagai kelas internal non-statis memiliki referensi implisit ke objek Aktivitas melampirkan, konteksnya, dan seluruh hirarki Tampilan yang dibuat oleh aktivitas tersebut. Referensi ini mencegah Kegiatan dari sampah dikumpulkan sampai pekerjaan latar belakang AsyncTask selesai. Jika koneksi pengguna lambat, dan / atau unduhan besar, kebocoran memori jangka pendek ini bisa menjadi masalah - misalnya jika orientasi berubah beberapa kali (dan Anda tidak membatalkan tugas yang sedang dijalankan), atau pengguna menavigasi jauh dari Kegiatan.
  • AsyncTask memiliki karakteristik eksekusi yang berbeda tergantung pada platform yang dijalankannya: sebelum API level 4 AsyncTasks dijalankan secara serial pada satu utas latar belakang; dari API level 4 hingga API level 10, AsyncTasks mengeksekusi pada genangan hingga 128 utas; dari API level 11 dan seterusnya AsyncTask mengeksekusi serial pada satu utas latar belakang (kecuali jika Anda menggunakan beban berlebih executeOnExecutormetode dan menyediakan pelaksana alternatif). Kode yang berfungsi dengan baik ketika dijalankan secara serial pada ICS dapat pecah ketika dijalankan secara bersamaan pada Gingerbread, katakanlah, jika Anda memiliki dependensi order-of-eksekusi yang tidak disengaja.

Jika Anda ingin menghindari kebocoran memori jangka pendek, memiliki karakteristik eksekusi yang terdefinisi dengan baik di semua platform, dan memiliki basis untuk membangun penanganan jaringan yang benar-benar kuat, Anda mungkin ingin mempertimbangkan:

  1. Menggunakan pustaka yang melakukan pekerjaan yang bagus untuk Anda - ada perbandingan bagus antara librari jaringan pertanyaan ini, atau
  2. Menggunakan sebuah Service atau IntentService sebagai gantinya, mungkin dengan PendingIntent untuk mengembalikan hasilnya melalui Activity's onActivityResult metode.

Pendekatan IntentService

Sisi bawah:

  • Lebih banyak kode dan kompleksitas daripada AsyncTask, meskipun tidak sebanyak yang Anda pikirkan
  • Akan antri permintaan dan menjalankannya pada tunggal utas latar belakang. Anda dapat dengan mudah mengontrol ini dengan mengganti IntentService dengan yang setara Service implementasi, mungkin suka yang ini.
  • Um, aku tidak bisa memikirkan orang lain sekarang

Sisi atas:

  • Menghindari masalah kebocoran memori jangka pendek
  • Jika aktivitas Anda dimulai ulang saat operasi jaringan sedang dalam penerbangan, ia masih dapat menerima hasil unduhan melalui nya onActivityResult metode
  • Platform yang lebih baik dari AsyncTask untuk membangun dan menggunakan kembali kode jaringan yang kuat. Contoh: jika Anda perlu melakukan upload penting, Anda bisa melakukannya AsyncTask dalam sebuah Activity, tetapi jika konteks pengguna-beralih keluar dari aplikasi untuk mengambil panggilan telepon, sistem mungkin bunuh aplikasi sebelum unggahan selesai. ini kecil kemungkinannya untuk membunuh aplikasi dengan aktif Service.
  • Jika Anda menggunakan versi konkuren Anda sendiri IntentService (seperti yang saya tautkan di atas) Anda dapat mengontrol tingkat konkurensi melalui Executor.

Ringkasan implementasi

Anda dapat menerapkan IntentService untuk melakukan unduhan pada satu utas latar belakang cukup mudah.

Langkah 1: Buat IntentService untuk melakukan unduhan. Anda dapat memberi tahu apa yang harus diunduh melalui Intent ekstra, dan lulus a PendingIntent digunakan untuk mengembalikan hasilnya ke 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);
        }
    }
}

Langkah 2: Daftarkan layanan dalam manifes:

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

Langkah 3: Memanggil layanan dari Aktivitas, meneruskan objek PendingResult yang akan digunakan Layanan untuk mengembalikan hasilnya:

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

Langkah 4: Tangani hasilnya di 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);
}

Proyek github yang berisi proyek lengkap Android-Studio / gradle yang lengkap tersedia sini.


118
2018-01-22 13:17



  1. Jangan gunakan strictMode (hanya dalam mode debug)
  2. Jangan ubah versi SDK
  3. Jangan gunakan utas yang terpisah

Gunakan Layanan atau AsyncTask

Lihat juga pertanyaan Stack Overflow:

android.os.NetworkOnMainThreadException mengirim email dari Android


59
2017-08-18 09:18



Lakukan tindakan jaringan di utas lain

Sebagai contoh:

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

Dan tambahkan ini ke AndroidManifest.xml

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

51
2017-12-24 14:33



Anda menonaktifkan mode ketat menggunakan kode berikut:

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

Ini tidak disarankan: menggunakan AsyncTaskantarmuka.

Kode lengkap untuk kedua metode


46
2017-10-24 07:10



Operasi berbasis jaringan tidak dapat dijalankan di utas utama. Anda perlu menjalankan semua tugas berbasis jaringan pada utas anak atau menerapkan AsyncTask.

Beginilah cara Anda menjalankan tugas di utas anak:

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

39
2018-01-14 06:14



Masukkan kode Anda di dalam:

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

Atau:

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

37
2017-07-28 10:43