सवाल मैं android.os.NetworkOnMainThreadException को कैसे ठीक करूं?


रु। रीडर के लिए मेरे एंड्रॉइड प्रोजेक्ट को चलाते समय मुझे एक त्रुटि मिली।

कोड:

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

और यह नीचे त्रुटि दिखाता है:

android.os.NetworkOnMainThreadException

मैं इस समस्या को कैसे हल कर सकता हूं?


1982
2018-06-14 12:02


मूल


इस ब्लॉग पोस्ट को पढ़ें अधिक जानकारी के लिए NetworkOnMainThreadException पर। यह बताता है कि यह एंड्रॉइड 3.0 और उसके बाद क्यों होता है। - Adrian Monk
संस्कार ट्रैक पर होने के लिए पहले एंड्रॉइड में नेटवर्क अनुरोधों के बारे में पढ़ें, तो मैं "वॉली" का अध्ययन करने की सिफारिश करूंगा। - Anuj Sharma
इस मुद्दे को हल करने वाले कई वैकल्पिक पुस्तकालय हैं। कई सूचीबद्ध हैं इस पृष्ठ के नीचे। यदि आप और अधिक प्राप्त करते हैं, तो हम उन्हें लेते हैं :) - Snicolas
आपको मुख्य (UI) थ्रेड से अलग धागे पर इंटरनेट गतिविधियों को चलाने की आवश्यकता है - Naveed Ahmad
stackoverflow.com/questions/16439587/...    उपरोक्त लिंक अच्छा है - nguyenvangiangbn


जवाब:


यह अपवाद तब फेंक दिया जाता है जब कोई एप्लिकेशन अपने मुख्य थ्रेड पर नेटवर्किंग ऑपरेशन करने का प्रयास करता है। अपना कोड चलाएं 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
    }
}

कार्य को निष्पादित कैसे करें:

में MainActivity.java फ़ाइल आप इस लाइन को अपने भीतर जोड़ सकते हैं oncreate() तरीका

new RetrieveFeedTask().execute(urlToRssFeed);

इसे जोड़ने के लिए मत भूलना AndroidManifest.xml फ़ाइल:

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

2240
2018-06-14 12:15



मुझे लगता है कि यह ध्यान देने योग्य है कि उपरोक्त कोड स्निपेट को उप-वर्ग (आंतरिक वर्ग) माना जाता है, अधिमानतः निजी। इस तरह जब AsyncTask समाप्त होता है, तब भी आप अपनी कक्षा के अंदरूनी हिस्सों में हेरफेर कर सकते हैं। - dyslexicanaboko
असल में मैंने वही बात की जैसा आपने ऊपर बताया है लेकिन मुझे इस त्रुटि का सामना करना पड़ रहा है java.lang.RuntimeException: थ्रेड के अंदर हैंडलर नहीं बना सकता जिसे Looper.prepare () नहीं कहा जाता है - Dhruv Tyagi
यह वास्तव में गलत जवाब है। मैं हर समय लोगों के कोड में आ जाता हूं, और इसे हर समय इसे ठीक करने के लिए परेशान करना पड़ता है। AsyncTask का उपयोग नेटवर्क गतिविधि के लिए नहीं किया जाना चाहिए, क्योंकि यह गतिविधि से जुड़ा हुआ है, लेकिन गतिविधि जीवन चक्र नहीं है। इस कार्य के साथ डिवाइस को घुमाने पर चल रहा है अपवाद और आपके ऐप को क्रैश कर देगा। एक IntentService का उपयोग करें जो इसके बजाय SQLite डेटाबेस में डेटा छोड़ देता है। - Brill Pappin
सावधानी, AsyncTask अक्सर गतिविधि गतिविधि संचालन के लिए उपयोग किया जाता है जब यह नहीं होना चाहिए। इसकी जीवन चक्र गतिविधि के साथ समन्वयित नहीं है। डेटा लाने के लिए, आपको एक इरादा सेवा और दृश्य के पीछे डेटाबेस का उपयोग करना चाहिए। - Brill Pappin
मैं दृढ़ता से ऐसे मामलों के लिए AsyncTask लोडर का सुझाव देता हूं। - Roman Gherta


आपको लगभग हमेशा थ्रेड पर या असीमित कार्य के रूप में नेटवर्क संचालन करना चाहिए।

पर यह है यदि आप परिणामों को स्वीकार करने के इच्छुक हैं, तो इस प्रतिबंध को हटाने के लिए और डिफ़ॉल्ट व्यवहार को ओवरराइड करना संभव है।

जोड़ें:

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

StrictMode.setThreadPolicy(policy); 

आपकी कक्षा में,

तथा

एंड्रॉइड manifest.xml फ़ाइल में इस अनुमति को जोड़ें:

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

परिणाम:

आपका ऐप (स्पॉटी इंटरनेट कनेक्शन के क्षेत्रों में) उत्तरदायी बन जाएगा और लॉक हो जाएगा, उपयोगकर्ता धीमेपन को समझता है और उसे बल मारना पड़ता है, और आप गतिविधि प्रबंधक को अपने ऐप को मारने और उपयोगकर्ता को यह बताते हुए जोखिम देते हैं कि ऐप बंद हो गया है।

प्रतिक्रिया के लिए डिजाइन करने के लिए एंड्रॉइड के अच्छे प्रोग्रामिंग प्रथाओं पर कुछ अच्छी युक्तियां हैं: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


557
2018-02-15 06:59



यह एक बहुत बुरा विचार है। समाधान मुख्य धागे पर नेटवर्क IO से बचने के लिए है (स्वीकृत उत्तर शो के रूप में)। - MByD
इसके साथ आप केवल अपनी असली समस्या को छुपाते हैं। - Alex
@TwistedUmbrella AsyncTask कोड का एक पृष्ठ नहीं जोड़ता है, यह 6 लाइनें जोड़ता है (कक्षा घोषणा, एनोटेशन ओवरराइड, doInBackground घोषणा, 2 समापन ब्रैकेट और एक कॉल करने के लिए execute())। दूसरी ओर, जैसा कि आप उल्लेख करते हैं, साइट से भी एक ही fetch UI प्रतिक्रिया में एक महत्वपूर्ण अंतराल लाता है। आलसी मत बनो। - Zoltán
@TwistedUmbrella मूर्ख मत बनो। यह है कि कितने खराब आवेदन किए जाते हैं। चाहे वह एक टेक्स्ट फ़ाइल या छवि गैलरी डाउनलोड कर रहा हो, आपको सर्वोत्तम प्रथाओं का पालन करना चाहिए। और मुख्य धागे पर नेटवर्क IO चलाना एक सर्वोत्तम अभ्यास नहीं है। - States
Upvoted। यह उत्तर सही है, और कई प्रोग्रामर जो न तो बेवकूफ हैं और न ही बेवकूफ हैं, लेकिन जिन्हें केवल सिंचन की आवश्यकता होती है (यानी यह ऐप को अवरुद्ध करना होगा) कॉल करें, यह वही है जो आवश्यक है। मैं खुश हूं कि एंड्रॉइड डिफ़ॉल्ट रूप से अपवाद फेंकता है (आईएमएचओ यह करने के लिए एक बहुत ही उपयोगी "चीज है!) - लेकिन मुझे यह कहते हुए भी बहुत खुशी है कि" धन्यवाद, लेकिन - यह वास्तव में मेरा इरादा है "और ओवरराइड करना यह। - Adam


मैंने एक नई समस्या का उपयोग करके इस समस्या को हल किया 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



प्रत्येक बार जब आप एक नेटवर्क ऑपरेशन करना चाहते हैं तो एक नया धागा बनाने के बजाय, आप एक थ्रेड एक्जिक्यूटर सेवा का भी उपयोग कर सकते हैं। - Alex Lockwood
सरल लेकिन खतरनाक। गुमनाम रननेबल में संलग्न वर्ग (उदा। आपकी गतिविधि या टुकड़ा) का एक निहित संदर्भ है, जो थ्रेड पूरा होने तक इसे कचरा होने से रोकता है। आपको कम से कम प्रक्रिया को प्राथमिकता सेट करनी चाहिए। बैकग्राउंड, अन्यथा यह धागा मुख्य / ui थ्रेड के समान प्राथमिकता पर चलाएगा, जीवन चक्र विधियों और ui फ्रेम दर के साथ संघर्ष (कोरियोग्राफर से लॉग में चेतावनियों के लिए देखें)। - Stevie
@Stevie प्राथमिकता कैसे सेट करें? न तो धावक और न ही निष्पादक सेवा के पास ऐसी एक सेटटर विधि है - J. K.
@ J.K। एक कस्टम थ्रेड फैक्टरी के साथ अपने निष्पादक सेवा की आपूर्ति करें और इसे वापस करने से पहले थ्रेड पर थ्रेड.सेट प्राथमिकता को कॉल करें। - Stevie
किसी नेटवर्क कॉल (जो अवरुद्ध होगा) करने के इरादे से किसी चीज़ के लिए प्राथमिकता सेट करना ओवरकिल लगता है। - john16384


आप नेटवर्क नहीं कर सकते हैं आई / ओ यूआई थ्रेड पर मधुकोश का। तकनीकी रूप से, यह है एंड्रॉइड के पुराने संस्करणों पर संभव है, लेकिन यह वास्तव में एक बुरा विचार है क्योंकि इससे आपके ऐप का जवाब देना बंद हो जाएगा, और परिणामस्वरूप ओएस बुरी तरह व्यवहार करने के लिए आपके ऐप को मार सकता है। पृष्ठभूमि पृष्ठभूमि पर अपना नेटवर्क लेनदेन करने के लिए आपको पृष्ठभूमि प्रक्रिया चलाने या AsyncTask का उपयोग करने की आवश्यकता होगी।

इसके बारे में एक लेख है पीले रंग की थ्रेडिंग एंड्रॉइड डेवलपर साइट पर जो इस के लिए एक अच्छा परिचय है, और यह आपको यथार्थवादी रूप से यहां प्रदान किए जा सकने वाले उत्तर की एक बेहतर गहराई प्रदान करेगा।


124
2018-06-14 12:07





स्वीकार्य उत्तर में कुछ महत्वपूर्ण नीचे-पक्ष हैं। जब तक आप नेटवर्किंग के लिए AsyncTask का उपयोग करने की सलाह नहीं दी जाती है वास्तव में पता है कि तुम क्या कर रहे हो। नीचे के कुछ पक्षों में शामिल हैं:

  • AsyncTask को गैर स्थैतिक आंतरिक वर्गों के रूप में बनाया गया है, जिसमें गतिविधि गतिविधि, इसके संदर्भ, और उस गतिविधि द्वारा बनाई गई संपूर्ण दृश्य पदानुक्रम के लिए एक अंतर्निहित संदर्भ है। यह संदर्भ एसिंक टास्क के काम को पूरा होने तक गतिविधि को कचरा होने से रोकता है। यदि उपयोगकर्ता का कनेक्शन धीमा है, और / या डाउनलोड बड़ा है, तो ये शॉर्ट-टर्म मेमोरी लीक एक समस्या बन सकती है - उदाहरण के लिए यदि अभिविन्यास कई बार बदलता है (और आप निष्पादन कार्यों को रद्द नहीं करते हैं), या उपयोगकर्ता नेविगेट करता है गतिविधि से दूर।
  • AsyncTask में निष्पादित प्लेटफॉर्म के आधार पर अलग निष्पादन विशेषताओं हैं: एपीआई स्तर 4 से पहले AsyncTasks एक पृष्ठभूमि थ्रेड पर क्रमशः निष्पादित करता है; एपीआई स्तर 4 के माध्यम से एपीआई स्तर 4 से, AsyncTasks 128 धागे तक के पूल पर निष्पादित; एपीआई स्तर 11 से आगे AsyncTask क्रमशः एक पृष्ठभूमि थ्रेड पर निष्पादित करता है (जब तक आप ओवरलोडेड का उपयोग नहीं करते executeOnExecutorविधि और एक वैकल्पिक निष्पादक की आपूर्ति)। कोड जो ठीक काम करता है जब आईसीएस पर क्रमशः चलते हैं तो जिंजरब्रेड पर समवर्ती रूप से निष्पादित किया जा सकता है, अगर आपके पास अनजान ऑर्डर-ऑफ-निष्पादन निर्भरता है।

यदि आप शॉर्ट-टर्म मेमोरी लीक से बचना चाहते हैं, तो सभी प्लेटफार्मों में अच्छी तरह से परिभाषित निष्पादन विशेषताओं को परिभाषित करें, और वास्तव में मजबूत नेटवर्क हैंडलिंग बनाने के लिए आधार है, तो आप इस पर विचार करना चाहेंगे:

  1. एक लाइब्रेरी का उपयोग करना जो आपके लिए यह अच्छा काम करता है - नेटवर्किंग libs की एक अच्छी तुलना है यह प्रश्न, या
  2. इसका उपयोग करना Service या IntentService इसके बजाय, शायद एक के साथ PendingIntent गतिविधि के माध्यम से परिणाम वापस करने के लिए onActivityResult तरीका।

इरादा सेवा दृष्टिकोण

नीचे पक्षों:

  • से अधिक कोड और जटिलता AsyncTask, हालांकि आप जितना सोच सकते हैं उतना नहीं
  • कतार अनुरोध करेंगे और उन्हें एक पर चलाएंगे एक पृष्ठभूमि धागा आप आसानी से इसे बदलकर नियंत्रित कर सकते हैं IntentService समकक्ष के साथ Service कार्यान्वयन, शायद पसंद है यह वाला
  • उम, मैं वास्तव में वास्तव में किसी अन्य के बारे में नहीं सोच सकता

ऊपर पक्षों:

  • अल्पकालिक स्मृति रिसाव समस्या से बचें
  • यदि नेटवर्क ऑपरेशंस इन-फ्लाइट के दौरान आपकी गतिविधि पुनरारंभ होती है तो भी इसे डाउनलोड के परिणाम प्राप्त हो सकते हैं onActivityResult तरीका
  • AsyncTask को मजबूत नेटवर्किंग कोड बनाने और पुन: उपयोग करने के लिए बेहतर प्लेटफॉर्म। उदाहरण: यदि आपको एक महत्वपूर्ण अपलोड करने की आवश्यकता है, तो आप इसे कर सकते हैं AsyncTask एक में Activity, लेकिन यदि उपयोगकर्ता कॉन्फ़्रेंस ऐप से फोन-कॉल करने के लिए स्विच करता है, तो सिस्टम हो सकता है अपलोड पूर्ण होने से पहले ऐप को मार दें। यह है संभावना कम एक सक्रिय के साथ एक आवेदन को मारने के लिए Service
  • यदि आप अपने स्वयं के समवर्ती संस्करण का उपयोग करते हैं IntentService (जैसा कि मैंने उपरोक्त लिंक किया है) आप के माध्यम से समवर्ती स्तर को नियंत्रित कर सकते हैं Executor

कार्यान्वयन सारांश

आप एक कार्यान्वित कर सकते हैं IntentService एक पृष्ठभूमि पृष्ठभूमि धागे पर आसानी से डाउनलोड करने के लिए।

चरण 1: एक बनाएँ IntentService डाउनलोड करने के लिए। आप इसे बता सकते हैं कि किसके माध्यम से डाउनलोड करना है Intent अतिरिक्त है, और इसे पास करें PendingIntent परिणाम को वापस करने के लिए उपयोग करने के लिए 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);
        }
    }
}

चरण 2: मैनिफेस्ट में सेवा पंजीकृत करें:

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

चरण 3: गतिविधि से सेवा को आमंत्रित करें, एक लंबितResult ऑब्जेक्ट को पारित करें जो सेवा परिणाम लौटने के लिए उपयोग करेगा:

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

चरण 4: परिणाम को निष्क्रियता पर संभाल लें परिणाम:

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

एक पूर्ण काम कर रहे एंड्रॉइड-स्टूडियो / ग्रेडल प्रोजेक्ट वाली एक जिथब परियोजना उपलब्ध है यहाँ


118
2018-01-22 13:17



IntentService ऐसा करने का सही तरीका है, अपमानजनक नहीं है क्योंकि AsyncTask बिल्कुल ऐसा करने का तरीका नहीं है। - Brill Pappin
@ ब्रिलपैपिन मैं लगभग पूरी तरह से सहमत हूं और AsyncTask की कमियों पर जोर देने के लिए पुनः शब्द दिया है। (मुझे अभी भी लगता है कि एक हैं बहुत छोटा मामलों की संख्या जहां - यदि आप वास्तव में जानते हैं कि आप क्या कर रहे हैं - यह पराक्रम AsyncTask का उपयोग करने के लिए ठीक हो, लेकिन स्वीकृत उत्तर किसी भी कमी को इंगित नहीं करता है और एंड्रॉइड के अच्छे के लिए रास्ता बहुत लोकप्रिय है)। - Stevie
क्या आपको वास्तव में आवश्यकता है IllustrativeRSS? क्या होगा यदि आप आरएसएस सामान के साथ काम नहीं कर रहे हैं? - Cullub


  1. सख्त मोड का उपयोग न करें (केवल डीबग मोड में)
  2. एसडीके संस्करण मत बदलें
  3. एक अलग थ्रेड का प्रयोग न करें

सेवा या AsyncTask का प्रयोग करें

स्टैक ओवरफ़्लो प्रश्न भी देखें:

android.os.NetworkOnMainThreadException एंड्रॉइड से एक ईमेल भेज रहा है


59
2017-08-18 09:18



शायद इस बिंदु पर जोर देने लायक है कि यदि आप किसी सेवा का उपयोग करते हैं तो आपको अभी भी एक अलग थ्रेड बनाने की आवश्यकता होगी - मुख्य थ्रेड पर सेवा कॉलबैक चलाएं। एक इरादा सेवा, दूसरी तरफ, पृष्ठभूमि थ्रेड पर हैडलइन्टेंट विधि को चलाती है। - Stevie
आपको लंबे समय तक चलने वाले कार्यों के लिए AsyncTask का उपयोग नहीं करना चाहिए! दिशानिर्देश अधिकतम 2 से 3 सेकंड निर्दिष्ट करते हैं। - Dage


किसी अन्य धागे पर नेटवर्क क्रियाएं करें

उदाहरण के लिए:

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

और इसे AndroidManifest.xml में जोड़ें

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

51
2017-12-24 14:33



लेकिन जब हम थ्रेड खत्म करते हैं तो हम कैसे पता लगा सकते हैं ताकि हम यूआई थ्रेड में अगले कार्यों को पूरा कर सकें? AsyncTask ऐसा करने की सुविधा प्रदान करता है। क्या चलने योग्य धागे का उपयोग करने के लिए ऐसा करने का कोई तरीका है? - Piyush Soni
यह चरणबद्ध रूप से आपके कोड चरण को संसाधित करेगा, इसलिए कोड समाप्त होने के बाद, आपको हैंडलर को UI थ्रेड पर वापस उपयोग करने की आवश्यकता है - henry4343
mobileorchard.com/... - henry4343
आप async कार्य या मंशा सेवा का उपयोग कर सकते हैं, क्योंकि यह कार्यकर्ता धागे पर निष्पादित है। - Chetan Chaudhari