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




thread-exceptions (24)

    **Use like this in Your Activity**

    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 inten=new Intent(getApplicationContext(),ComposeMail.class);
            //intent.putParcelableArrayListExtra("valuesList", value);

            startActivity(inten);



                }
            }).start();
        }
    });

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

कोड:

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

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


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

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


आपको एंड्रॉइड पर यूआई थ्रेड पर नेटवर्क ऑपरेशंस को लागू करने की अनुमति नहीं है। आपको नेटवर्क से संबंधित संचालन करने के लिए 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);
        }


    }
}

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


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

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

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

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

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

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

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

AsynTask का उपयोग करने के लिए पहली सत्यापित उत्तर सलाह है। हां, यह एक समाधान है, लेकिन आजकल अप्रचलित है, क्योंकि वहां नए उपकरण हैं।

String getUrl() {
    return "SomeUrl";
}

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

private void processResponse(Object o) {

}

GetUrl विधि यूआरएल पता प्रदान करती है, और इसे मुख्य धागे पर निष्पादित किया जाएगा।

makeCallParseResponse (..) - वास्तविक काम करता है

प्रक्रिया प्रतिक्रिया (..) - मुख्य धागे पर परिणाम संभाल लेंगे।

एसिंक्रोनस निष्पादन के लिए कोड इस तरह दिखेगा:

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

AsyncTask की तुलना में, यह विधि शेड्यूलर को मनमाने ढंग से कई बार स्विच करने की अनुमति देती है (कहें, एक शेड्यूलर पर डेटा लाएं और उन डेटा को किसी अन्य (कहें, Scheduler.computation ()) पर संसाधित करें। आप अपने शेड्यूलर को भी परिभाषित कर सकते हैं।

इस लाइब्रेरी का उपयोग करने के लिए, build.gradle फ़ाइल में निम्न पंक्तियां शामिल करें:

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

अंतिम निर्भरता में .mainThread () शेड्यूलर के लिए समर्थन शामिल है।

नहीं है RX-जावा के लिए एक उत्कृष्ट ebook


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

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


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

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

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

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

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

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

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

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

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


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

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

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


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

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

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

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


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

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

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

उपाय:

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

मार्ग:

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

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

परंतु:

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

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

कैसे?

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

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

इस प्रकार आप एक बच्चे धागे में एक कार्य चलाते हैं:

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

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

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

जोड़ें:

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


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

http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html


नए 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

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

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

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

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

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

नीचे पक्षों:

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

ऊपर पक्षों:

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

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

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

चरण 1: डाउनलोड करने के लिए एक IntentService बनाएं। आप यह बता सकते हैं कि Intent अतिरिक्त के माध्यम से क्या डाउनलोड करना है, और Activity को परिणाम वापस करने के लिए इसका उपयोग करने के लिए PendingIntent पास करें:

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

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


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

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

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

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


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

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

HTTP पर आरएसटी

आमतौर पर जेसन, एक्सएमएल या कुछ और हो सकता है

पूर्ण एपीआई एक्सेस

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

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://.com/a/42899766/1024412 )।

आरएसटी एपीआई एक्सेस से एक

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

आयन

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

कृपया msysmilu के महान उत्तर को पढ़ें ( https://.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

निम्नलिखित कोड को ऑनरेट विधि (टुकड़ा, गतिविधि) या कन्स्ट्रक्टर (संवाद) में जोड़ें:

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/


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


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

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

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

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

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

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

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

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

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

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





thread-exceptions