java - मैं android.os.NetworkOnMainThreadException को कैसे ठीक करूं?




thread-exceptions (20)

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

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

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

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

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


अपना कोड अंदर रखें:

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

या:

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

आप निम्न कोड का उपयोग कर सख्त मोड को अक्षम करते हैं:

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

यह अनुशंसित नहीं है : AsyncTask इंटरफ़ेस का उपयोग करें।

दोनों तरीकों के लिए पूर्ण कोड


आपको किसी भी नेटवर्क ऑपरेशन, फ़ाइल I / O, या SQLite डेटाबेस संचालन जैसे मुख्य थ्रेड (UI थ्रेड) पर कोई समय लेने वाला कार्य नहीं करना चाहिए। तो इस तरह के ऑपरेशन के लिए, आपको एक कार्यकर्ता धागा बनाना चाहिए, लेकिन समस्या यह है कि आप अपने कार्यकर्ता धागे से सीधे यूआई से संबंधित ऑपरेशन नहीं कर सकते हैं। इसके लिए, आपको Handler का उपयोग करना होगा और Message पास करना होगा।

इन सभी चीजों को सरल बनाने के लिए, एंड्रॉइड AsyncTask , AsyncTaskLoader , CursorLoader या IntentService जैसे विभिन्न तरीकों को प्रदान करता है। तो आप इनमें से किसी भी अपनी आवश्यकताओं के अनुसार उपयोग कर सकते हैं।


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

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

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

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

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

त्रुटि मुख्य थ्रेड में लंबे समय तक चलने वाले संचालन निष्पादित करने के कारण है, आप AsynTask या Thread का उपयोग कर समस्या को आसानी से सुधार सकते हैं। बेहतर संचालन के लिए आप इस लाइब्रेरी AsyncHTTPClient को चेकआउट कर सकते हैं।

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

मेरे लिए यह था:

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

जिस डिवाइस पर मैं अपने ऐप का परीक्षण कर रहा था वह 4.1.2 था जो एसडीके संस्करण 16 है!

सुनिश्चित करें कि लक्ष्य संस्करण आपकी एंड्रॉइड लक्ष्य लाइब्रेरी जैसा ही है। यदि आप अनिश्चित हैं कि आपकी लक्षित लाइब्रेरी क्या है, तो अपने प्रोजेक्ट -> बिल्ड पथ -> एंड्रॉइड पर राइट क्लिक करें, और यह टिकाया जाना चाहिए।

साथ ही, जैसा कि अन्य ने उल्लेख किया है, इंटरनेट तक पहुंचने के लिए सही अनुमतियां शामिल हैं:

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

मैंने एक नई Thread का उपयोग करके इस समस्या को हल किया।

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

यह अपवाद मुख्य धागे पर किए गए किसी भी भारी कार्य के कारण होता है यदि उस प्रदर्शन कार्य में बहुत अधिक समय लगता है

इससे बचने के लिए, हम धागे या निष्पादकों का उपयोग करके इसे संभाल सकते हैं

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

यह एंड्रॉइड 3.0 और ऊपर में होता है। एंड्रॉइड 3.0 और उसके बाद से, उन्होंने मुख्य थ्रेड / यूआई थ्रेड में चलने से नेटवर्क ऑपरेशंस (इंटरनेट का उपयोग करने वाले फ़ंक्शंस) का उपयोग करके प्रतिबंधित किया है (आपके निर्माण से क्या स्पॉन्स और गतिविधि में फिर से शुरू करने के तरीकों पर)।

यह नेटवर्क संचालन के लिए अलग धागे का उपयोग करने के लिए प्रोत्साहित करना है। नेटवर्क गतिविधियों को सही तरीके से कैसे करें, इस बारे में अधिक जानकारी के लिए AsyncTask देखें।


सरल शब्दों में,

यूआई थ्रेड में नेटवर्क काम न करें

उदाहरण के लिए, यदि आप एक HTTP अनुरोध करते हैं, तो यह एक नेटवर्क कार्रवाई है।

उपाय:

  1. आपको एक नया थ्रेड बनाना है
  2. या AsyncTask कक्षा का उपयोग करें

मार्ग:

अपने सभी काम अंदर रखो

  1. नए धागे की run() विधि
  2. या doInBackground() कक्षा के doInBackground() विधि।

परंतु:

जब आप नेटवर्क प्रतिक्रिया से कुछ प्राप्त करते हैं और इसे अपने दृश्य पर दिखाना चाहते हैं (जैसे टेक्स्टव्यू में प्रदर्शन प्रतिक्रिया संदेश), तो आपको UI थ्रेड पर वापस लौटना होगा

यदि आप ऐसा नहीं करते हैं, तो आपको ViewRootImpl$CalledFromWrongThreadException

कैसे?

  1. AsyncTask का उपयोग करते समय, onPostExecute() विधि से दृश्य अपडेट करें
  2. या runOnUiThread() विधि को कॉल करें और run() विधि के अंदर अद्यतन देखें।

स्पष्ट रूप से कुछ स्पष्ट करने के लिए:

मुख्य धागा मूल रूप से यूआई धागा है।

तो कह रहे हैं कि आप मुख्य धागे में नेटवर्किंग परिचालन नहीं कर सकते हैं, इसका मतलब है कि आप यूआई थ्रेड में नेटवर्किंग ऑपरेशंस नहीं कर सकते हैं, जिसका मतलब है कि आप *runOnUiThread(new Runnable() { ... }* किसी अन्य थ्रेड के अंदर ब्लॉक में नेटवर्किंग ऑपरेशंस नहीं कर सकते , या तो।

(मुझे लगता है कि मुझे यह पता लगाने की कोशिश कर रहा था कि मुझे अपने मुख्य धागे के अलावा कहीं और त्रुटि क्यों मिल रही थी। यही कारण है कि; इस धागे ने मदद की; और उम्मीद है कि यह टिप्पणी किसी और की मदद करेगी।)


Spektom का शीर्ष जवाब सही काम करता है।

यदि आप AsyncTask इनलाइन लिख रहे हैं और कक्षा के रूप में विस्तार नहीं कर रहे हैं, और इसके शीर्ष पर, यदि AsyncTask से प्रतिक्रिया प्राप्त करने की आवश्यकता है, तो कोई नीचे get() विधि का उपयोग कर सकता है।

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

(उनके उदाहरण से।)


एंड्रॉइड एनोटेशन का उपयोग करना एक विकल्प है। यह आपको पृष्ठभूमि थ्रेड में किसी भी विधि को चलाने की अनुमति देगा:

// normal method
private void normal() {
    doSomething(); // do something in background
}

@Background
protected void doSomething() 
    // run your networking code here
}

ध्यान दें, हालांकि यह सादगी और पठनीयता के लाभ प्रदान करता है, इसके इसके नुकसान हैं।


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

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

जोड़ें:

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


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

उदाहरण: मान लें कि आप एक यूआरएल से छवि डाउनलोड करना चाहते हैं: https://www.samplewebsite.com/sampleimage.jpg

AsyncTask का उपयोग कर समाधान: क्रमशः हैं।

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


    }
}

नोट: एंड्रॉइड मैनिफेस्ट फ़ाइल में इंटरनेट अनुमति जोड़ने के लिए मत भूलना। यह एक आकर्षण की तरह काम करेगा। :)


एंड्रॉइड पर, नेटवर्क थ्रेड मुख्य थ्रेड पर नहीं चलाया जा सकता है। आप नेटवर्क संचालन करने के लिए थ्रेड, AsyncTask (शॉर्ट-रनिंग कार्य), सेवा (लंबे समय से चलने वाले कार्यों) का उपयोग कर सकते हैं।


नए Threadऔर AsynTask समाधान पहले ही समझाया गया है।

AsyncTaskआदर्श रूप से छोटे परिचालनों के लिए इस्तेमाल किया जाना चाहिए। सामान्य ThreadAndroid के लिए बेहतर नहीं है।

HandlerHandlerThread और Handler का उपयोग करके वैकल्पिक समाधान पर नज़र डालेंHandler

HandlerThread

एक नया धागा शुरू करने के लिए हैंडी क्लास जिसमें लूपर है। लूपर का उपयोग हैंडलर कक्षाएं बनाने के लिए किया जा सकता है। ध्यान दें कि start()अभी भी कहा जाना चाहिए।

हैंडलर:

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

उपाय:

  1. सर्जन करना HandlerThread

  2. start()पर कॉल करेंHandlerThread

  3. बनाएँ Handlerहो रही द्वारा LooperसेHanlerThread

  4. Runnableऑब्जेक्ट में अपने नेटवर्क ऑपरेशन से संबंधित कोड एम्बेड करें

  5. Runnableकार्य सबमिट करेंHandler

नमूना कोड स्निपेट, जो पता है 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);

इस दृष्टिकोण का उपयोग करने के पेशेवर:

  1. Thread/AsyncTaskप्रत्येक नेटवर्क ऑपरेशन के लिए नया बनाना महंगा है। Thread/AsyncTaskनष्ट कर दिया जाएगा और अगले नेटवर्क के संचालन के लिए फिर से बनाया। लेकिन साथ Handlerऔर HandlerThreadदृष्टिकोण, आप कई नेटवर्क ऑपरेशंस (रननेबल कार्यों के रूप में) का HandlerThreadउपयोग करके एकल में सबमिट कर सकते हैं Handler

यद्यपि ऊपर एक बड़ा समाधान पूल है, कोई भी उल्लेख नहीं किया गया है com.koushikdutta.ion: https://github.com/koush/ion

यह असीमित और उपयोग करने में बहुत आसान है:

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

यह काम। सिर्फ डॉ लुइजी के जवाब को थोड़ा आसान बना दिया।

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





thread-exceptions