'Android.os.NetworkOnMainThreadException' को कैसे ठीक करें?


2393

रुपये के लिए अपने Android प्रोजेक्ट को चलाते समय मुझे एक त्रुटि मिली।

कोड:

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

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


131
अधिक जानकारी के लिए NetworkOnMainThreadException पर इस ब्लॉग पोस्ट को पढ़ें । यह बताता है कि यह एंड्रॉइड 3.0 और इसके बाद के संस्करण पर क्यों होता है।
एड्रियन मोंक

6
संस्कार ट्रैक पर होने के लिए पहले Android में नेटवर्क अनुरोधों के बारे में पढ़ें, फिर मैं "वॉली" का अध्ययन करने की सलाह दूंगा।
अनुज शर्मा

3
कई वैकल्पिक पुस्तकालय हैं जो इस मुद्दे को हल करते हैं। कई इस पृष्ठ के नीचे सूचीबद्ध हैं । यदि आप अधिक हो गए हैं, तो हम उन्हें ले जाते हैं :)
Snicolas

आपको मुख्य (यूआई) थ्रेड से अलग थ्रेड पर इंटरनेट गतिविधियां चलाने की आवश्यकता है
नावेद अहमद

"एंड्रॉइड के पिछले संस्करणों में एक बग के कारण, सिस्टम ने मुख्य मोड पर एक टीसीपी सॉकेट के लिए एक सख्त-मोड उल्लंघन के रूप में ध्वजांकित नहीं किया था। एंड्रॉइड 7.0 इस बग को ठीक करता है। इस व्यवहार को प्रदर्शित करने वाले ऐप्स अब android.os फेंकते हैं। NetworkOnMainThreadException। " - तो हम में से कुछ ने हाल ही तक इसे नहीं मारा है! डेवलपर
Jay

जवाबों:


2547

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

37
मुझे लगता है कि यहां यह ध्यान देने योग्य है कि ऊपर कोड स्निपेट को एक उपवर्ग (आंतरिक वर्ग) माना जाता है, अधिमानतः निजी। इस तरह जब AsyncTask खत्म हो जाता है, तब भी आप अपनी कक्षा के इनर को हेरफेर कर सकते हैं।
डिस्लेक्सिकानबोको

4
असल में मैं ऐसा ही किया था के रूप में यू ऊपर उल्लेख किया है, लेकिन मीटर इस त्रुटि का सामना करना पड़ java.lang.RuntimeException: धागा कि Looper.prepare () आह्वान नहीं किया अंदर हैंडलर नहीं बना सकता
ध्रुव त्यागी

68
यह बिल्कुल गलत जवाब है। मैं लोगों के कोड में यह सब समय पर आता हूं, और हर समय इसे ठीक करने के लिए कष्टप्रद। AsyncTask का उपयोग नेटवर्क गतिविधि के लिए नहीं किया जाना चाहिए, क्योंकि यह गतिविधि से जुड़ा हुआ है, लेकिन गतिविधि जीवनचक्र नहीं। इस कार्य के साथ डिवाइस को घुमाने से एक अपवाद हो जाएगा और आपके ऐप को क्रैश कर देगा। IntentService का उपयोग करें जो डेटा को sqlite डेटाबेस में छोड़ता है।
ब्रिल पप्पिन 19

5
सावधानी, AsyncTask अक्सर गतिविधि नेटवर्क संचालन के लिए उपयोग किया जाता है जब यह नहीं होना चाहिए। इसकी जीवनचक्र गतिविधि के साथ तालमेल नहीं है। डेटा लाने के लिए, आपको एक IntentService और दृश्य के पीछे डेटाबेस का उपयोग करना चाहिए।
ब्रिल पप्पिन

1
@BrillPappin, FWIW, इस Android डेवलपर गाइड का उपयोग करता है AsyncTask, और एक विन्यास परिवर्तन का ख्याल रखता है।
हेजुडे

676

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

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

जोड़ें:

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

StrictMode.setThreadPolicy(policy); 

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

तथा

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

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

परिणाम:

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

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


456
यह बहुत बुरा विचार है। समाधान मुख्य थ्रेड पर नेटवर्क IO से बचने के लिए है (जैसा कि स्वीकृत उत्तर दिखाता है)।
MByD

74
इससे आप केवल अपनी वास्तविक समस्या को छिपाते हैं।
एलेक्स

28
@TwistedUmbrella AsyncTask में कोड का एक पेज नहीं जोड़ा गया है, इसमें 6 लाइनें (क्लास डिक्लेरेशन, ओवरराइड एनोटेशन, doInBackgroundडिक्लेरेशन, 2 क्लोजिंग ब्रैकेट्स और एक कॉल टू execute()) मिलती हैं । दूसरी ओर, यहां तक ​​कि एक साइट से एक भी लाने के रूप में आप उल्लेख यूआई जवाबदेही में एक महत्वपूर्ण अंतराल लाता है। आलसी मत बनो।
ज़ोल्टन

19
मुझे लगता है कि यह सही समाधान है यदि आप कोड का एक नमूना हिस्सा चला रहे हैं, यह देखने के लिए कि क्या उचित AsyncTask को लागू करने से पहले कुछ काम करता है। इसलिए मैंने इस उत्तर को उकेरा है, हालांकि जैसा कि अन्य सभी ने कहा है, यह उत्पादन ऐप में नहीं किया जाना चाहिए, केवल एक देव परीक्षण के लिए एक त्वरित समाधान के रूप में।
हुकेड 82२

94
Upvoted। यह उत्तर सही है, और कई प्रोग्रामर के लिए जो न तो भोले हैं और न ही मूर्ख, लेकिन जिन्हें बस एक SYNCHRONOUS की आवश्यकता होती है (यानी: इस ऐप को ब्लॉक करना होगा ) कॉल, यह ठीक उसी की जरूरत है। मुझे खुशी है कि एंड्रॉइड डिफ़ॉल्ट रूप से अपवाद को फेंकता है (IMHO यह एक बहुत "उपयोगी" चीज़ है!) - लेकिन मैं "थैंक्स" कहने के लिए उतना ही खुश हूं, लेकिन - यह वास्तव में मेरा इरादा है और ओवरराइड करने के लिए यह।
एडम

427

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

7
हर बार जब आप नेटवर्क ऑपरेशन करना चाहते हैं, तो एक नया धागा बनाने के बजाय, आप एक एकल थ्रेड निष्पादक सेवा का भी उपयोग कर सकते हैं।
एलेक्स लॉकवुड

66
सरल लेकिन खतरनाक। अनाम रननेबल में संलग्न वर्ग (जैसे आपकी गतिविधि या टुकड़ा) का एक अंतर्निहित संदर्भ है, जब तक कि थ्रेड पूरा नहीं हो जाता तब तक इसे कचरा एकत्र करने से रोकता है। आपको कम से कम प्राथमिकता को Process.BACKGROUND पर सेट करना चाहिए, अन्यथा यह थ्रेड मुख्य / ui थ्रेड के रूप में एक ही प्राथमिकता पर चलेगा, जीवनचक्र के तरीकों और ui फ्रेम दरों (कोरियोग्राफर से लॉग में चेतावनी के लिए बाहर देखें) के साथ प्रतिस्पर्धा।
स्टीव

1
@Stevie प्राथमिकता कैसे निर्धारित करें? न तो चलने योग्य और न ही निष्पादक के पास ऐसी कोई सेटर विधि है
JK

1
@JK एक कस्टम थ्रेडफैक्टरी के साथ अपने ExecutorService की आपूर्ति करें और इसे वापस करने से पहले थ्रेड पर थ्रेड पर जाएं।
स्टीव

1
"एंड्रॉइड में सीधे थ्रेड्स का उपयोग करना हतोत्साहित किया जाता है। इससे अधिक समस्याएं होती हैं जो इसे हल करता है" उस पर विस्तार से ध्यान दें? वास्तव में AsyncTask के लिए वास्तव में उसी के द्वारा पदावनत किया जा रहा है ... Techyourchance.com/asynctask-deprecated
Fran Marzoa

169

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

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

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

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

IntentService दृष्टिकोण

नीचे पक्षों:

  • से अधिक कोड और जटिलता 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: गतिविधि से सेवा का आह्वान करें, एक PendingResult ऑब्जेक्ट पास करना जो सेवा परिणाम का उपयोग करने के लिए उपयोग करेगी:

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

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


IntentService ऐसा करने का सही तरीका है, न कि उखाड़ फेंकना क्योंकि AsyncTask ठीक उसी तरह है जैसे यह नहीं करना है।
ब्रिल पप्पिन 14

3
@BrillPappin मैं लगभग पूरी तरह से सहमत हूं और AsyncTask की कमियों पर जोर देने के लिए फिर से शब्द दिया है। (मुझे अभी भी लगता है कि बहुत कम संख्या में ऐसे मामले हैं - यदि आप वास्तव में जानते हैं कि आप क्या कर रहे हैं - यह AsyncTask का उपयोग करने के लिए ठीक हो सकता है, लेकिन स्वीकृत उत्तर किसी भी तरह की कमियां नहीं बताता है और यह अच्छे के लिए बहुत लोकप्रिय है। Android के)।
स्टेवी

1
क्या आपको वास्तव में जरूरत है IllustrativeRSS? यदि आप RSS सामान के साथ काम नहीं कर रहे हैं तो क्या होगा?
कुलुब

मेरी राय में, Google को प्रोग्रामर्स की तरफ बर्डन डालने के बजाय कचरा संग्रहण के अपने बुरे कार्यान्वयन को बदलना चाहिए। यह OS की जिम्मेदारी है। यदि कोई प्रोग्रामर एंड्रॉइड कार्यान्वयन में मूलभूत समस्या के कारण इंटेंटसेवा या सेवा का उपयोग करता है, तो कुछ वर्षों के बाद Google कहेगा कि इंटेंट सर्विस खराब अभ्यास भी है और कुछ और सुझाव देता है। और यह कहानी जारी है ... इसलिए Google डेवलपर्स को एंड्रॉइड खराब मेमोरी प्रबंधन को हल करना चाहिए न कि प्रोग्रामर को।
सईद खलफीनजाद

मैं बस यह कहने जा रहा हूं: यह उत्तर एक बेहतर विकल्प की तुलना में परियोजना को साझा करने के तरीके की तरह लगता है AsyncTask। त्रुटि यूआई को पिछड़ने से डेवलपर्स को रोकने के लिए थी, जरूरी नहीं कि उन्हें इंटेंट / सेवाओं के एक समूह के साथ सुरक्षा को जोखिम में डाल दें।
गाड़ी का

144

आप हनीकॉम्ब पर UI थ्रेड पर नेटवर्क I / O नहीं कर सकते । तकनीकी तौर पर, यह है Android के पिछले संस्करणों पर संभव है, लेकिन यह एक बहुत बुरा विचार है, क्योंकि यह आपका ऐप्स प्रतिसाद करना बंद कर देगी, और ओएस बुरी तरह बर्ताव किया जा रहा है के लिए अपने अनुप्रयोग की हत्या हो सकती है। आपको बैकग्राउंड थ्रेड पर अपने नेटवर्क ट्रांजेक्शन को करने के लिए एक बैकग्राउंड प्रोसेस को चलाने या AsyncTask का उपयोग करने की आवश्यकता होगी।

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


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

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

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

Android.os.NetworkOnMainThreadException Android से एक ईमेल भेज रहा है


8
शायद इस बात पर जोर देने के लायक है कि यदि आप एक सेवा का उपयोग करते हैं, तो आपको अभी भी एक अलग धागा बनाने की आवश्यकता होगी - सेवा कॉलबैक मुख्य धागे पर चलते हैं। दूसरी ओर एक आशय सेवा, एक पृष्ठभूमि सूत्र पर अपने onHandleIntent विधि को चलाता है।
स्टेवई

आपको लंबे समय तक चलने वाले संचालन के लिए एक AsyncTask का उपयोग नहीं करना चाहिए! दिशानिर्देश 2 से 3 सेकंड अधिकतम निर्दिष्ट करते हैं।
दिगंबर

76

नेटवर्क क्रिया किसी अन्य थ्रेड पर करें

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

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

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

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

5
लेकिन जब थ्रेड खत्म हो जाता है तो हम कैसे पता लगा सकते हैं कि हम यूआई थ्रेड में कार्यों के अगले सेट को पूरा कर सकते हैं? AsyncTask ऐसा करने की सुविधा प्रदान करता है। क्या रन करने योग्य थ्रेड्स का उपयोग करने का एक तरीका है?
पीयूष सोनी

3
यह आपके कोड को चरण दर चरण संसाधित करेगा, इसलिए कोड समाप्त होने पर, आपको UI थ्रेड में वापस हैंडलर का उपयोग करने की आवश्यकता है
henry4343

1
आप async कार्य या आशय सेवा का उपयोग कर सकते हैं, क्योंकि यह कार्यकर्ता थ्रेड पर निष्पादित होता है।
चेतन चौधरी

63

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

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

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

दोनों विधियों के लिए पूर्ण कोड


2
हाँ ANR त्रुटि आ जाएगी। मतलब 5 सेकंड में ऐप का जवाब नहीं।
मुहम्मद मुबाशीर

11
यह वास्तव में बुरा जवाब है। आपको थ्रेड की नीति नहीं बदलनी चाहिए लेकिन बेहतर कोड लिखना चाहिए: मुख्य थ्रेड पर नेटवर्क संचालन न करें!
श्क्शनाइडर

@ संदीप आप और अन्य दर्शकों को भी इसे पढ़ना चाहिए। stackoverflow.com/a/18335031/3470479
प्रखर 1001

54

नेटवर्क-आधारित संचालन को मुख्य थ्रेड पर नहीं चलाया जा सकता है। आपको चाइल्ड थ्रेड पर सभी नेटवर्क-आधारित कार्यों को चलाने या AsyncTask को लागू करने की आवश्यकता है।

यह है कि आप किसी कार्य को बाल सूत्र में कैसे चलाते हैं:

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

बेनामी रननेबल सबसे अच्छा तरीका नहीं है, क्योंकि इसमें एनक्लोजिंग क्लास का एक निहित संदर्भ है और इसे जीसी एड होने से रोका जाता है जब तक कि धागा पूरा न हो जाए! इसके अलावा यह धागा मुख्य प्राथमिकता के रूप में / यूएस थ्रेड के रूप में चलेगा, जीवन चक्र विधियों और UI फ्रेम दर के साथ प्रतिस्पर्धा करेगा!
योषा अलायूबे

49

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

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

दूसरा सबसे पहले 11 से ऊपर आपी के लिए सबसे अच्छा होगा
रोहित गोस्वामी

46

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

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


46

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

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

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

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


6
@Gavriel यह आपके द्वारा एनोटेट की गई हर चीज़ का डुप्लिकेट बनाता है, चाहे वह एक विधि, गतिविधि, टुकड़ा, सिंगलटन आदि हो, इसलिए इसमें दोगुना कोड है और इसे संकलित करने में अधिक समय लगता है। लाइब्रेरी में बग के कारण इसमें कुछ समस्याएँ भी हो सकती हैं। डिबगिंग और त्रुटियों को ढूंढना अधिक कठिन हो जाएगा।
ओलेक्सी

43

त्रुटि मुख्य धागे में लंबे समय तक चलने वाले संचालन को निष्पादित करने के कारण है, आप असिनटस्क या थ्रेड का उपयोग करके आसानी से समस्या को ठीक कर सकते हैं । बेहतर हैंडलिंग के लिए आप इस लाइब्रेरी 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
    }
});

42

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

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


40

स्पेकटॉम का शीर्ष उत्तर एकदम सही है।

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

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

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


5
उपयोग get()करना एक बुरा विचार है ... यह AsyncTask को फिर से "सिंक" बनाता है
सेल्विन

क्या इससे बेहतर कोई अलग रास्ता है? @ सेल्विन
सिवाग 1

2
मुझे लगता है कि आप परिणाम के बारे में मुख्य सूत्र की जानकारी दे सकते हैं। उदाहरण के लिए, परिणाम सहित मुख्य धागे के लिए एक प्रसारण भेजें।
चाइन गैरी

32

यह केवल हनीकॉम्ब एसडीके या उच्चतर को लक्षित करने वाले अनुप्रयोगों के लिए फेंका गया है । पहले एसडीके संस्करणों को लक्षित करने वाले अनुप्रयोगों को अपने मुख्य ईवेंट लूप थ्रेड्स पर नेटवर्किंग करने की अनुमति है।

त्रुटि एसडीके चेतावनी है!


28

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

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

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

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

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

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

11
मैं आपको समझाता हूं कि आप यहां क्या कर रहे हैं: NetworkOnMainThreadExceptionवह अभिभावक है जो आपको बता रहा है: अपने खुद के पैर पर गोली मत चलाइए ... आपका समाधान यह है: चलिए उस अतीत की ओर लौटते हैं जब कोई अभिभावक नहीं था - अब मैं अपने पर गोली चला सकता हूं स्वतंत्र रूप से पैर
सेल्विन

1
मैंने भी यह तरीका अपनाया और कोई समस्या नहीं हुई। अभिभावक भी कभी-कभी उधम मचाते हैं।
फ्रैक्टलबोब

25

इसे अपनी गतिविधि में उपयोग करें

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

23

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

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

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

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


22

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

इससे बचने के लिए, हम इसे थ्रेड्स या एक्ज़ीक्यूटर्स का उपयोग करके संभाल सकते हैं

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

18

इस सवाल पर कई शानदार जवाब पहले से ही हैं, लेकिन उन जवाबों को पोस्ट किए जाने के बाद से बहुत सारे महान पुस्तकालय सामने आए हैं। यह एक प्रकार का नौसिखिया-मार्गदर्शक है।

मैं नेटवर्क संचालन और प्रत्येक के लिए एक समाधान या दो प्रदर्शन के लिए कई उपयोग मामलों को कवर करूंगा ।

HTTP पर ReST

आमतौर पर Json, XML या कुछ और हो सकता है

पूर्ण एपीआई पहुंच

मान लीजिए कि आप एक ऐसा ऐप लिख रहे हैं जो उपयोगकर्ताओं को स्टॉक की कीमतों, ब्याज दरों और क्यूरेसी एक्सचेंज दरों को ट्रैक करने देता है। आपको एक Json API मिलती है जो कुछ इस तरह दिखती है:

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)

स्क्वायर से रेट्रोफिट

यह कई एंडपॉइंट्स के साथ एपीआई के लिए एक उत्कृष्ट विकल्प है और आपको आयन या वॉली जैसे अन्य पुस्तकालयों के साथ व्यक्तिगत रूप से कोड करने के बजाय रेस्ट एंडपॉइंट घोषित करने की अनुमति देता है। (वेबसाइट: http://square.github.io/retrofit/ )

आप वित्त एपीआई के साथ इसका उपयोग कैसे करते हैं?

build.gradle

अपने मॉड्यूल स्तर 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);
    }
}

फाइनेंसफ्रेगमेंट स्निपेट

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

यदि आपके एपीआई को भेजने के लिए एक एपीआई कुंजी या उपयोगकर्ता टोकन जैसे अन्य शीर्षलेख की आवश्यकता होती है, तो रिट्रोफिट यह आसान बनाता है (विवरण के लिए यह भयानक उत्तर देखें: https://stackoverflow.com/a/42899766/1024412 )।

ReST API एक्सेस को बंद कर देता है

मान लीजिए कि आप एक "मूड वेदर" ऐप बना रहे हैं जो उपयोगकर्ताओं को जीपीएस लोकेशन दिखता है और उस क्षेत्र के वर्तमान तापमान की जाँच करता है और उन्हें मूड बताता है। इस प्रकार के ऐप को एपीआई एंडपॉइंट घोषित करने की आवश्यकता नहीं है; यह बस एक एपीआई समापन बिंदु का उपयोग करने में सक्षम होने की जरूरत है।

आयन

इस प्रकार की पहुँच के लिए यह एक महान पुस्तकालय है।

कृपया msysmilu का शानदार उत्तर पढ़ें ( https://stackoverflow.com/a/28559884/1024412 )

HTTP के माध्यम से छवियों को लोड करें

फ़ायर

वॉली का उपयोग रीस्ट एपीआई के लिए भी किया जा सकता है, लेकिन अधिक जटिल सेटअप के कारण मुझे आवश्यक है कि ऊपर से स्क्वायर से रिट्रोफिट का उपयोग करना पसंद करें ( http://square.github.io/retrofit/ )

मान लीजिए कि आप एक सोशल नेटवर्किंग ऐप बना रहे हैं और दोस्तों की प्रोफाइल पिक्चर लोड करना चाहते हैं।

build.gradle

इस लाइन को अपने मॉड्यूल स्तर buid.gradle में जोड़ें:

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

ImageFetch.java

वॉली को रेट्रोफिट से अधिक सेटअप की आवश्यकता है। आपको RequestQueue, ImageLoader और ImageCache सेटअप करने के लिए इस तरह एक वर्ग बनाने की आवश्यकता होगी, लेकिन यह बहुत बुरा है:

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

छवि जोड़ने के लिए अपने लेआउट xml फ़ाइल में निम्न जोड़ें:

<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

निम्नलिखित कोड onCreate मेथड (Fragment, Activity) या कंस्ट्रक्टर (डायलॉग) में जोड़ें:

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

पिकासो

स्क्वायर से एक और उत्कृष्ट पुस्तकालय। कृपया कुछ महान उदाहरणों के लिए साइट देखें: http://square.github.io/picasso/


16

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

UI थ्रैड में काम न करें

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

समाधान:

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

मार्ग:

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

  1. run() नए धागे की विधि
  2. या doInBackground() AsyncTask क्लास का तरीका।

परंतु:

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

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

कैसे?

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

12

आप अपने कोड के एक भाग को बंद करने के लिए एक और थ्रेड में ले जाने में सक्षम हैं main threadऔर ANR , NetworkOnMainThreadException , IllegalStateException (जैसे कि संभवत: यह यूआई को लंबे समय तक यूआई लॉक कर सकता है) पर डेटाबेस को एक्सेस नहीं कर सकता है।

कुछ दृष्टिकोण हैं जिन्हें आपको चुनना चाहिए स्थिति पर निर्भर करता है

जावा थ्रेड या एंड्रॉइड हैंडलर

जावा थ्रेड्स केवल एक बार उपयोग होते हैं और इसकी रन विधि को निष्पादित करने के बाद मर जाते हैं।

हैंडलरथ्रेड एक नया धागा शुरू करने के लिए एक आसान वर्ग है जिसमें एक लूपर है।

AsyncTask

AsyncTask को थ्रेड और हैंडलर के आसपास एक सहायक वर्ग के रूप में डिज़ाइन किया गया है और यह सामान्य थ्रेडिंग फ्रेमवर्क का गठन नहीं करता है। AsyncTasks को छोटे संचालन के लिए आदर्श रूप से उपयोग किया जाना चाहिए (कुछ सेकंड सबसे अधिक।) यदि आपको लंबे समय तक थ्रेड चलाने की आवश्यकता है, तो यह अत्यधिक अनुशंसा की जाती है कि आप java.util.concurrent द्वारा प्रदान किए गए विभिन्न API का उपयोग करें। निष्पादक , थ्रेडपूल एक्ज़ीक्यूटर और FutureTask

थ्रेड पूल कार्यान्वयन थ्रेडपूल एक्ज़ीक्यूटर , शेड्यूल थ्रेडपूल एक्ज़ीक्यूटर ...

ThreadPoolExecutor वर्ग जो ExecutorService को लागू करता है जो थ्रेड पूल (जैसे, कोर पूल का आकार, अधिकतम पूल आकार, जीवित समय, आदि) पर ठीक नियंत्रण देता है।

ScheduledThreadPoolExecutor - एक वर्ग जो थ्रेडपूल एक्ज़ीक्यूटर का विस्तार करता है। यह दिए गए विलंब या समय-समय पर कार्यों को निर्धारित कर सकता है।

FutureTask

FutureTask अतुल्यकालिक प्रसंस्करण करता है, हालांकि, यदि परिणाम अभी तक तैयार नहीं है या प्रसंस्करण पूरा नहीं हुआ है, तो कॉलिंग गेट () थ्रेड ब्लॉक हो जाएगा

AsyncTaskLoaders

AsyncTaskLaders के रूप में वे बहुत सारी समस्याओं को हल करते हैं जो AsyncTask में निहित हैं

IntentService

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

JobScheduler

प्रभावी रूप से, आपको एक सेवा तैयार करनी होगी और JobInfo.Builder का उपयोग करके एक नौकरी बनानी होगी जो सेवा को चलाने के लिए आपके मानदंड को निर्दिष्ट करती है।

RxJava

अवलोकन योग्य अनुक्रमों का उपयोग करके अतुल्यकालिक और घटना-आधारित कार्यक्रमों की रचना के लिए पुस्तकालय।

Coroutines (कोटलिन)

इसका मुख्य सार यह है कि यह अतुल्यकालिक कोड को तुल्यकालिक जैसा बनाता है

और अधिक पढ़ें यहाँ , यहाँ , यहाँ , यहाँ


मेरे लिए काम किया ... मैंने बड़े पैमाने पर AsyncTask का उपयोग किया है, लेकिन जब एक कार्य चल रहा है तो अन्य प्रतीक्षा करेंगे। मैं इसका समाधान करना चाहता हूं। अब executeonexecutor के साथ काम कर रहा है। आइए देखें कि यह कम मेमोरी डिवाइस पर कैसे व्यवहार करेगा।
सूरज शिंगडे

कृपया विधि पर एक नज़र डालें: asyncTask.executeOnExecutor (AsyncTask.THREAD_POOL_EXECUTOR, params); अपना कार्य एक साथ चलाने के लिए
yoAlex5

10

हालांकि ऊपर एक विशाल समाधान पूल है, जिसका कोई उल्लेख नहीं किया गया है 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
    }
});

10

नई Threadऔर AsyncTask समाधान पहले ही बताए जा चुके हैं।

AsyncTaskआदर्श रूप से छोटे संचालन के लिए उपयोग किया जाना चाहिए। साधारणThread Android के लिए बेहतर नहीं है।

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

HandlerThread

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

हैंडलर:

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

समाधान:

  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

8

RxAndroidइस समस्या का एक और बेहतर विकल्प है और यह हमें थ्रेड बनाने और फिर Android UI थ्रेड पर परिणाम पोस्ट करने के झंझटों से बचाता है। हमें केवल उन थ्रेड्स को निर्दिष्ट करने की आवश्यकता है जिन पर कार्यों को निष्पादित करने की आवश्यकता है और सब कुछ आंतरिक रूप से नियंत्रित किया जाता है।

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. निर्दिष्ट करके (Schedulers.io()), RxAndroid getFavoriteMusicShows() एक अलग धागे पर चलेगा ।

  2. का उपयोग करके AndroidSchedulers.mainThread()हम यूआई धागे पर इस प्रत्यक्ष निरीक्षण करने के लिए चाहते हैं, यानी हम अपने चाहते onNext()कॉलबैक यूआई धागे पर के नाम से जाना


8

मुख्य धागा UI थ्रेड है, और आप मुख्य थ्रेड में एक ऑपरेशन नहीं कर सकते हैं जो उपयोगकर्ता इंटरैक्शन को अवरुद्ध कर सकता है। आप इसे दो तरीकों से हल कर सकते हैं:

इस तरह से मुख्य थ्रेड में कार्य करने के लिए बल

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

या एक साधारण हैंडलर बनाएं और यदि आप चाहें तो मुख्य थ्रेड को अपडेट करें।

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

और थ्रेड उपयोग को रोकने के लिए:

newHandler.removeCallbacks(runnable);

अधिक जानकारी के लिए इसे देखें: दर्द रहित थ्रेडिंग


धन्यवाद। संस्करण 1 जब ऑनक्रिएट में पहली क्रिया के रूप में जोड़ते हैं तो मदद करता है।
इंगो

7

यह काम। बस डॉ.लुइजी का जवाब थोड़ा सरल था।

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

7

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


7

मुख्य (UI) थ्रेड से नेटवर्क संसाधनों तक पहुँच इस अपवाद का कारण बनता है। इस समस्या से बचने के लिए नेटवर्क संसाधन तक पहुँचने के लिए एक अलग थ्रेड या AsyncTask का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.