कई बार AsyncTask निष्पादित करें


127

मेरी गतिविधि में मैं एक वर्ग का उपयोग करता हूं जो कि AsyncTask से मिलता है और एक पैरामीटर जो उस AsyncTask का एक उदाहरण है। जब मैं फोन करता हूं तो mInstanceOfAT.execute("")सब ठीक है। लेकिन जब मैं एक अपडेट बटन दबाता हूं तो ऐप क्रैश हो जाता है जो फिर से AsyncTask (नेटवर्क काम के दौरान काम नहीं करता है) को कॉल करता है। कारण तब एक अपवाद दिखाई देता है जो कहता है

कार्य निष्पादित नहीं कर सकता: कार्य पहले ही निष्पादित हो चुका है (एक कार्य को केवल एक बार निष्पादित किया जा सकता है)

मैंने अस्सिटकट्स के उदाहरण के लिए रद्द (सत्य) कॉल करने की कोशिश की है, लेकिन यह या तो काम नहीं करता है। अब तक का एकमात्र समाधान एसिंत्स्क के नए उदाहरण बनाना है। क्या यह सही तरीका है?

धन्यवाद।

जवाबों:


217

AsyncTask उदाहरणों का उपयोग केवल एक बार किया जा सकता है।

इसके बजाय, बस अपने कार्य को कॉल करें जैसे new MyAsyncTask().execute("");

AsyncTask API डॉक्स से:

थ्रेडिंग नियम

इस वर्ग को ठीक से काम करने के लिए कुछ थ्रेडिंग नियमों का पालन करना चाहिए:

  • कार्य थ्रेड UI थ्रेड पर बनाया जाना चाहिए।
  • निष्पादित (Params ...) UI थ्रेड पर लागू किया जाना चाहिए।
  • OnPreExecute (), onPostExecute (परिणाम), doInBackground (परम ...), onProgressUpdate (प्रगति ...) को मैन्युअल रूप से कॉल न करें।
  • कार्य को केवल एक बार निष्पादित किया जा सकता है (यदि एक दूसरे निष्पादन का प्रयास किया जाता है तो अपवाद को फेंक दिया जाएगा।)

2
जो मैंने कहा वह मैंने किया है, क्या केवल यही संभावना है? क्योंकि मैं एक नई वस्तु बनाने के बजाय, संस्मरण को बचाना चाहता हूं।
दिनमान


@StevePrentice: यदि मैं प्रत्येक कार्य को नए कार्य () के साथ कार्य का एक उदाहरण बनाता हूं। (निष्पादित करें), सर्वर पर डेटा भेजने के लिए, निष्पादन के पूरा होने पर कचरा कलेक्टर स्मृति को कैसे जारी कर सकता है?
Ant4res

3
@ Ant4res, जब तक आप async कार्य उदाहरण का संदर्भ नहीं दे रहे हैं, तब तक GC मेमोरी जारी करेगा। हालाँकि, यदि आपके पास एक पृष्ठभूमि कार्य है, तो आप इसे doInBackground के अंदर एक लूप में करने पर विचार कर सकते हैं और प्रगति को अद्यतन करने के लिए publishProgress पर कॉल कर सकते हैं। या, एक और तरीका यह होगा कि आप अपने काम को बैकग्राउंड थ्रेड में रखें। यहाँ विभिन्न दृष्टिकोणों के बहुत सारे, लेकिन विवरण के बिना एक दूसरे पर सिफारिश नहीं कर सकते।
स्टीव प्रेंटिस

28

ASyncTask के आग-और-भुलाने के कारणों के कारण स्टीव प्रेंटिस के जवाब में बहुत अच्छी तरह से विस्तृत हैं - हालाँकि, जब तक आप कितनी बार आप ASyncTask को निष्पादित करते हैं, इस पर प्रतिबंधित है , तो आप वह काम करने के लिए स्वतंत्र हैं, जब आप धागा पसंद करते हैं। ।

अपने निष्पादन योग्य कोड को doInBackground () के भीतर एक लूप के अंदर रखें और प्रत्येक निष्पादन को ट्रिगर करने के लिए एक समवर्ती लॉक का उपयोग करें। आप publishProgress () / onProgressUpdate () का उपयोग करके परिणाम प्राप्त कर सकते हैं ।

उदाहरण:

class GetDataFromServerTask extends AsyncTask<Input, Result, Void> {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition tryAgain = lock.newCondition();
    private volatile boolean finished = false;

    @Override
    protected Void doInBackground(Input... params) {

        lock.lockInterruptibly();

        do { 
            // This is the bulk of our task, request the data, and put in "result"
            Result result = ....

            // Return it to the activity thread using publishProgress()
            publishProgress(result);

            // At the end, we acquire a lock that will delay
            // the next execution until runAgain() is called..
            tryAgain.await();

        } while(!finished);

        lock.unlock();
    }

    @Override
    protected void onProgressUpdate(Result... result) 
    {
        // Treat this like onPostExecute(), do something with result

        // This is an example...
        if (result != whatWeWant && userWantsToTryAgain()) {
            runAgain();
        }
    }

    public void runAgain() {
        // Call this to request data from the server again
        tryAgain.signal();
    }

    public void terminateTask() {
        // The task will only finish when we call this method
        finished = true;
        lock.unlock();
    }

    @Override
    protected void onCancelled() {
        // Make sure we clean up if the task is killed
        terminateTask();
    }
}

बेशक, यह ASyncTask के पारंपरिक उपयोग की तुलना में थोड़ा अधिक जटिल है, और आप वास्तविक प्रगति रिपोर्टिंग के लिए publishProgress () का उपयोग छोड़ देते हैं । लेकिन यदि स्मृति आपकी चिंता है, तो यह दृष्टिकोण रनटाइम के दौरान ढेर में केवल एक ASyncTask बनी रहेगी।


लेकिन बात यह है कि मैं दौड़ते समय एसिंस्कैस्क को फिर से निष्पादित नहीं करना चाहता, लेकिन इस कारण से कि यह खत्म हो गया है और डेटा को प्राप्त नहीं करना चाहिए जैसा कि इसे फिर से कॉल करना चाहिए।
दिनमान

वास्तव में आप इस तरह से केवल एक बार ASyncTask को निष्पादित करते हैं, और यदि डेटा onPublishProgress विधि के अंदर सही है (या चेक को कहीं और सौंप दें) तो आप जांच कर सकते हैं। मैंने कुछ समय पहले इसी तरह की समस्या के लिए इस पैटर्न का उपयोग किया था (ढेर सारे काम जल्दी उत्तराधिकार में निकाल दिए जा रहे थे, ढेर के आकार को जोखिम में डालते हुए)।
15.05 बजे

लेकिन क्या होगा अगर उस क्षण में सर्वर प्रतिक्रिया नहीं करता है, और मैं 10 सेकंड के बाद फिर से कोशिश करना चाहता हूं? AsyncTask पहले ही समाप्त हो चुका है, कठोरता। फिर मुझे इसे फिर से कॉल करने की आवश्यकता है
Dayerman

मैंने इसका मतलब बताने के लिए कुछ उदाहरण कोड जोड़े हैं। ASyncTask केवल तभी समाप्त होगी जब आप परिणाम से खुश होंगे और "terminateTask ()" पर कॉल करेंगे।
सीनहेड्स

1
यदि आप अंदर जाते IllegalMonitorStateExceptionहैं runAgain(द्वारा बुलाया जाता है onProgressUpdate) तो इसका उत्तर देखें: stackoverflow.com/a/42646476/2711811 । यह सुझाव देता है (और मेरे लिए काम करता है) कि / signal()a से घिरा होना चाहिए । यह कॉलिंग के समय के साथ करना पड़ सकता है । lockunlockpublishProgressonProgressUpdate
एंडी

2

मेरी भी यही समस्या थी। मेरे मामले में मेरे पास एक कार्य है जो मैं (में onCreate()और onResume() करना चाहता हूं । इसलिए मैंने अपने एसिंक्टस्क को स्थिर बना दिया, और इससे उदाहरण प्राप्त किया। अब हमारे सामने भी यही समस्या है।

तो मैंने onPostExecute () में क्या किया है:

instance = null;

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

if (instance == null){
    instance = new Task();
}
return instance;

PostExecute में विधि उदाहरण को खाली कर देगी और इसे पुनः बनाएगी। बेशक यह कक्षा के बाहर किया जा सकता है।


1

मैंने अपने रोटेशन कार्यों को स्थिर बना दिया है, जिसने फिर मुझे रोटेशन परिवर्तनों पर यूआई थ्रेड्स को संलग्न करने, अलग करने और पुन: भेजने में मदद की। लेकिन अपने सवाल पर वापस जाने के लिए, मैं क्या करता हूं यह देखने के लिए कि झंडा चल रहा है या नहीं। जब आप थ्रेड को पुनरारंभ करना चाहते हैं तो मैं जांचता हूं कि क्या रोटेशन कार्य चल रहा है यदि यह एक चेतावनी है। यदि यह नहीं है, तो मैं इसे शून्य बना देता हूं और फिर एक नया निर्माण करता हूं, जो आपके द्वारा देखी जा रही त्रुटि के आसपास काम करेगा। इसके अलावा, सफल समापन पर मैंने पूर्ण रोटेशन जागरूक कार्य को समाप्त कर दिया ताकि वह फिर से जाने के लिए तैयार हो।


0

हाँ, यह सच है, डॉक्टर का कहना है कि केवल एक एसिंत्स्क को ही अंजाम दिया जा सकता है।

हर बार आपको इसका उपयोग करने की आवश्यकता होती है जो आपको उदाहरण के लिए है:

// Any time if you need to call her
final FirmwareDownload fDownload = new FirmwareDownload();
fDownload.execute("your parameter");

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