क्या AsyncTask वास्तव में वैचारिक रूप से त्रुटिपूर्ण है या मैं सिर्फ कुछ याद कर रहा हूं?


264

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

समस्या साथ है AsyncTask। प्रलेखन के अनुसार यह

"थ्रेड और / या हैंडलर में हेरफेर किए बिना पृष्ठभूमि संचालन करने और UI थ्रेड पर परिणाम प्रकाशित करने की अनुमति देता है।"

उदाहरण तो यह बताता है कि कुछ अनुकरणीय showDialog()विधि को किस रूप में कहा जाता है onPostExecute()। यह, हालांकि, पूरी तरह से मेरे लिए Contextविरोधाभास लगता है, क्योंकि एक संवाद को दिखाने के लिए हमेशा एक वैध के संदर्भ की आवश्यकता होती है , और एक AsyncTask को कभी भी संदर्भ वस्तु के लिए एक मजबूत संदर्भ नहीं रखना चाहिए

कारण स्पष्ट है: क्या होगा यदि गतिविधि नष्ट हो जाती है जो कार्य को ट्रिगर करती है? यह हर समय हो सकता है, उदाहरण के लिए क्योंकि आपने स्क्रीन को फ़्लिप किया है। यदि यह कार्य उस संदर्भ का संदर्भ देगा, जिसने इसे बनाया है, तो आप न केवल एक बेकार संदर्भ ऑब्जेक्ट पर पकड़ रहे हैं (खिड़की नष्ट हो गई होगी और कोई यूआई इंटरैक्शन अपवाद के साथ विफल हो जाएगा!), आप जोखिम भी पैदा कर सकते हैं! स्मृति रिसाव।

जब तक मेरा तर्क यहाँ त्रुटिपूर्ण नहीं है, तब तक यह अनुवाद करता है: onPostExecute() पूरी तरह से बेकार है, क्योंकि यूआई थ्रेड पर चलने के लिए इस विधि के लिए क्या अच्छा है यदि आपके पास किसी भी संदर्भ तक पहुंच नहीं है? आप यहां कुछ भी सार्थक नहीं कर सकते।

एक वर्कअराउंड संदर्भ उदाहरणों को AsyncTask पर नहीं, बल्कि एक Handlerउदाहरण के लिए होगा। यह काम करता है: चूंकि एक हैंडलर शिथिल रूप से संदर्भ और कार्य को बांधता है, आप एक रिसाव (दाएं?) को जोखिम में डाले बिना उनके बीच संदेशों का आदान-प्रदान कर सकते हैं। लेकिन इसका मतलब यह होगा कि AsyncTask का आधार, अर्थात आपको हैंडलर से परेशान होने की आवश्यकता नहीं है, गलत है। यह हैंडलर को गाली देने जैसा भी लगता है, क्योंकि आप एक ही धागे पर संदेश भेज रहे हैं और प्राप्त कर रहे हैं (आप इसे यूआई थ्रेड पर बनाते हैं और इसके माध्यम से ऑनपोस्ट एक्स्यूट्यूट () जिसे यूआई थ्रेड पर भी निष्पादित किया जाता है) भेजें।

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

मेरा इसका समाधान (जैसा कि Droid-Fu लाइब्रेरी में लागू किया गया है ) है WeakReferenceकि यूनिक एप्लिकेशन ऑब्जेक्ट पर घटक नामों से उनके वर्तमान उदाहरणों के लिए मानचित्रण बनाए रखा जाए । जब भी कोई AsyncTask शुरू किया जाता है, तो यह उस मानचित्र में कॉलिंग संदर्भ को रिकॉर्ड करता है, और प्रत्येक कॉलबैक पर, यह उस मैपिंग से वर्तमान संदर्भ उदाहरण प्राप्त करेगा। यह सुनिश्चित करता है कि आप कभी भी बासी संदर्भ उदाहरण का संदर्भ नहीं लेंगे और आपके पास हमेशा कॉलबैक में एक वैध संदर्भ तक पहुंच होगी, ताकि आप वहां सार्थक यूआई काम कर सकें। यह भी लीक नहीं होता है, क्योंकि संदर्भ कमजोर होते हैं और साफ हो जाते हैं जब किसी दिए गए घटक का कोई उदाहरण अब मौजूद नहीं है।

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

अब मैं बस यह जानना चाहता हूं: क्या मैं केवल सामूहिक रूप से कुछ याद कर रहा हूं या क्या AsyncTask वास्तव में पूरी तरह से त्रुटिपूर्ण है? आपके अनुभव इसके साथ कैसे काम कर रहे हैं? आपने इन समस्या को कैसे हल किया?

आपके सहयोग के लिए धन्यवाद।


1
यदि आप जिज्ञासु हैं, तो हमने हाल ही में इग्निएटएंडसाइनटैस्क नामक इग्निशन कोर लाइब्रेरी में एक वर्ग जोड़ा है, जो नीचे दिए गए डायने द्वारा उल्लिखित कनेक्ट / डिस्कनेक्ट पैटर्न का उपयोग करके सभी कॉलबैक में टाइप-सेफ संदर्भ एक्सेस के लिए समर्थन जोड़ता है। यह अपवादों को फेंकने और एक अलग कॉलबैक में उन्हें संभालने की भी अनुमति देता है। Github.com/kaeppler/ignition-core/blob/master/src/com/github/…
Matthias

इस पर एक नज़र है: gist.github.com/1393552
Matthias

1
यह प्रश्न भी संबंधित है।
एलेक्स लॉकवुड

मैं async कार्य को एक सरणी सूची में जोड़ता हूं और उन सभी को एक निश्चित बिंदु पर बंद करना सुनिश्चित करता हूं।
नाइटस्कीकोड

जवाबों:


86

इस जैसे किसी और के बारे में क्या राय है:

class MyActivity extends Activity {
    Worker mWorker;

    static class Worker extends AsyncTask<URL, Integer, Long> {
        MyActivity mActivity;

        Worker(MyActivity activity) {
            mActivity = activity;
        }

        @Override
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                totalSize += Downloader.downloadFile(urls[i]);
                publishProgress((int) ((i / (float) count) * 100));
            }
            return totalSize;
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            if (mActivity != null) {
                mActivity.setProgressPercent(progress[0]);
            }
        }

        @Override
        protected void onPostExecute(Long result) {
            if (mActivity != null) {
                mActivity.showDialog("Downloaded " + result + " bytes");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mWorker = (Worker)getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = this;
        }

        ...
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new Worker(this);
        mWorker.execute(...);
    }
}

5
हां, mActivity होगी! = Null, लेकिन अगर आपके वर्कर इंस्टेंस का कोई संदर्भ नहीं है, तो कोई भी संदर्भ जो इंस्टेंस के साथ ही कचरा हटाने के अधीन होगा। यदि आपका कार्य हमेशा के लिए चलता है, तो आपके पास वैसे भी स्मृति रिसाव है (आपका कार्य) - यह उल्लेख करने के लिए नहीं कि आप फोन की बैटरी को निकाल रहे हैं। इसके अलावा, जैसा कि कहीं और उल्लेख किया गया है, आप onDestroy को शून्य करने के लिए mActivity सेट कर सकते हैं।
ईबोमाइक

13
OnDestroy () विधि शून्य करने के लिए mActivity सेट करती है। इससे कोई फर्क नहीं पड़ता कि कौन इससे पहले गतिविधि का संदर्भ रखता है, क्योंकि यह अभी भी चल रहा है। और गतिविधि की विंडो हमेशा ऑनडेस्ट्रो () कहे जाने तक मान्य होगी। वहाँ अशक्त करने के लिए, async कार्य पता चल जाएगा कि गतिविधि अब मान्य नहीं है। (। और एक config परिवर्तन, पिछली गतिविधि के OnDestroy () कहा जाता है और मुख्य लूप तो AsyncTask उन दोनों के बीच संसाधित पर कोई संदेश बिना अगले एक की OnCreate () रन एक असंगत स्थिति कभी नहीं देखेंगे जब)
hackbod

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

11
बैकग्राउंड में पहुंचने के लिए, आपको या तो mActivity के आसपास उचित सिंक्रोनाइज़ेशन रखना होगा और ऐसे समय में चलने के साथ निपटना होगा, या बैकग्राउंड थ्रेड को बस Context.getApplicationContext () पर ले जाना होगा, जो ऐप के लिए एक एकल वैश्विक उदाहरण है। आप क्या कर सकते हैं में आवेदन संदर्भ प्रतिबंधित है (उदाहरण के लिए डायलॉग की तरह कोई UI नहीं) और कुछ देखभाल की आवश्यकता है (पंजीकृत रिसीवर और सेवा बाइंडिंग को हमेशा के लिए छोड़ दिया जाएगा यदि आप उन्हें साफ नहीं करते हैं), लेकिन आम तौर पर कोड के लिए उपयुक्त है 'किसी विशेष घटक के संदर्भ से बंधा नहीं है।
हैकबॉड

4
यह अविश्वसनीय रूप से सहायक था, धन्यवाद डायने! काश दस्तावेजीकरण पहले स्थान पर अच्छा होता।
मथियास

20

कारण स्पष्ट है: क्या होगा यदि गतिविधि नष्ट हो जाती है जो कार्य को ट्रिगर करती है?

मैन्युअल रूप से गतिविधि को अलग AsyncTaskमें onDestroy()। मैन्युअल रूप से करने के लिए नई गतिविधि पुन: संबद्ध AsyncTaskमें onCreate()। इसके लिए या तो एक स्थिर आंतरिक वर्ग या एक मानक जावा वर्ग की आवश्यकता होती है, साथ ही शायद कोड की 10 लाइनें भी।


स्थैतिक संदर्भों से सावधान रहें - मैंने वस्तुओं को कचरा एकत्र करते हुए देखा है, भले ही उनके लिए स्थैतिक मजबूत संदर्भ थे। हो सकता है कि एंड्रॉइड के क्लास लोडर का एक साइड-इफ़ेक्ट, या एक बग भी हो, लेकिन स्टेटिक रेफ़रेंस एक गतिविधि जीवन-चक्र में राज्य के आदान-प्रदान का कोई सुरक्षित तरीका नहीं है। हालांकि, एप्लिकेशन ऑब्जेक्ट है, इसलिए मैं इसका उपयोग करता हूं।
Matthias

10
@ माथियास: मैंने स्थैतिक संदर्भों का उपयोग करने के लिए नहीं कहा। मैंने कहा कि एक स्थिर आंतरिक वर्ग का उपयोग करें। दोनों के नामों में "स्थिर" होने के बावजूद पर्याप्त अंतर है।
कॉमन्सवेयर जूल


5
मैं देख रहा हूँ - वे यहाँ कुंजी getLastNonConfigurationInstance () है, हालांकि स्थिर आंतरिक वर्ग नहीं है। एक स्थिर आंतरिक वर्ग अपने बाहरी वर्ग के लिए कोई निहित संदर्भ नहीं रखता है, इसलिए यह शब्दशः सादे सार्वजनिक वर्ग के बराबर है। बस एक चेतावनी: onRetainNonConfigurationInstance () एक गतिविधि बाधित होने पर (एक रुकावट फोन कॉल भी हो सकती है) कॉल करने की गारंटी नहीं है, इसलिए आपको onSetInstanceState () में अपने टास्क को सही मायने में ठोस बनाने के लिए पार्सल करना होगा। उपाय। लेकिन फिर भी, अच्छा विचार है।
मथायस

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

15

ऐसा लगता है कि यह केवल वैचारिक दोष से AsyncTaskथोड़ा अधिक है । यह संगतता समस्याओं द्वारा भी अनुपयोगी है। Android डॉक्स पढ़ा:

जब पहली बार पेश किया गया, तो AsyncTasks को एकल पृष्ठभूमि थ्रेड पर क्रमिक रूप से निष्पादित किया गया था। डोनट के साथ शुरू करते हुए, इसे थ्रेड्स के एक पूल में बदल दिया गया, जिससे कई कार्यों को समानांतर में संचालित किया जा सके। हनीकॉम शुरू करने, समानांतर निष्पादन के कारण होने वाली सामान्य अनुप्रयोग त्रुटियों से बचने के लिए कार्यों को एक ही थ्रेड पर निष्पादित किया जा रहा है। यदि आप वास्तव में समानांतर निष्पादन चाहते हैं, तो आप executeOnExecutor(Executor, Params...) इस पद्धति के संस्करण का उपयोग कर सकते हैंTHREAD_POOL_EXECUTOR ; हालाँकि, इसके उपयोग पर चेतावनी के लिए कमेंटरी देखें।

दोनों executeOnExecutor()और THREAD_POOL_EXECUTORकर रहे हैं एपीआई स्तर 11 में जोड़ा गया (एंड्रॉयड 3.0.x, मधुकोश)।

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

और यदि आप 2.x और 3.0+ दोनों को लक्षित करना चाहते हैं, तो सामान वास्तव में मुश्किल हो जाता है।

इसके अलावा, डॉक्स कहते हैं:

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


12

संभवतः हम सभी, जिसमें Google भी शामिल है, MVC के दृष्टिकोण AsyncTaskसे दुरुपयोग कर रहे हैं ।

एक गतिविधि एक नियंत्रक है , और नियंत्रक को उन कार्यों को शुरू नहीं करना चाहिए जो दृश्य को रेखांकित कर सकते हैं । यही है, मॉडल से AsyncTasks का उपयोग किया जाना चाहिए , एक वर्ग से जो गतिविधि जीवन चक्र के लिए बाध्य नहीं है - याद रखें कि रोटेशन के साथ गतिविधियां नष्ट हो जाती हैं। ( व्यू के अनुसार , आप आमतौर पर android.widget.Button जैसे उदाहरणों से व्युत्पन्न कक्षाएं प्रोग्राम नहीं करते हैं, लेकिन आप कर सकते हैं। आमतौर पर, केवल एक चीज जो आप व्यू के बारे में करते हैं वह है xml।)

दूसरे शब्दों में, AsyncTask डेरिवेटिव को गतिविधियों के तरीकों में रखना गलत है। OTOH, अगर हमें गतिविधियों में AsyncTasks का उपयोग नहीं करना चाहिए, तो AsyncTask अपना आकर्षण खो देता है: यह एक त्वरित और आसान फिक्स के रूप में विज्ञापित किया जाता था।


5

मुझे यकीन नहीं है कि यह सच है कि आप एक AsyncTask से एक संदर्भ के संदर्भ में स्मृति रिसाव का जोखिम उठाते हैं।

उन्हें लागू करने का सामान्य तरीका गतिविधि के तरीकों में से एक के दायरे में एक नया AsyncTask उदाहरण बनाना है। इसलिए यदि गतिविधि नष्ट हो जाती है, तो एक बार AsyncTask पूरा होने के बाद यह अनुपलब्ध नहीं होगा और फिर कचरा संग्रहण के लिए पात्र होगा? इसलिए गतिविधि का संदर्भ मायने नहीं रखेगा क्योंकि AsyncTask अपने आप ही घूमने नहीं लगेगा।


2
सच है - लेकिन क्या होगा अगर कार्य अनिश्चित काल तक अवरुद्ध हो? कार्य अवरुद्ध संचालन करने के लिए होते हैं, शायद वे भी जो कभी समाप्त नहीं होते हैं। वहां आपकी मेमोरी लीकेज है।
Matthias

1
कोई भी कर्मी जो अंतहीन लूप में कुछ करता है, या ऐसा कुछ जो सिर्फ I / O ऑपरेशन पर बंद होता है।
मथायस

2

अपनी गतिविधि पर एक सप्ताह का संदर्भ रखना अधिक मजबूत होगा:

public class WeakReferenceAsyncTaskTestActivity extends Activity {
    private static final int MAX_COUNT = 100;

    private ProgressBar progressBar;

    private AsyncTaskCounter mWorker;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task_test);

        mWorker = (AsyncTaskCounter) getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(this);
        }

        progressBar = (ProgressBar) findViewById(R.id.progressBar1);
        progressBar.setMax(MAX_COUNT);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_async_task_test, menu);
        return true;
    }

    public void onStartButtonClick(View v) {
        startWork();
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new AsyncTaskCounter(this);
        mWorker.execute();
    }

    static class AsyncTaskCounter extends AsyncTask<Void, Integer, Void> {
        WeakReference<WeakReferenceAsyncTaskTestActivity> mActivity;

        AsyncTaskCounter(WeakReferenceAsyncTaskTestActivity activity) {
            mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(activity);
        }

        private static final int SLEEP_TIME = 200;

        @Override
        protected Void doInBackground(Void... params) {
            for (int i = 0; i < MAX_COUNT; i++) {
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d(getClass().getSimpleName(), "Progress value is " + i);
                Log.d(getClass().getSimpleName(), "getActivity is " + mActivity);
                Log.d(getClass().getSimpleName(), "this is " + this);

                publishProgress(i);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (mActivity != null) {
                mActivity.get().progressBar.setProgress(values[0]);
            }
        }
    }

}

यह वैसा ही है जैसा हमने पहले Droid-Fu के साथ किया था। हम संदर्भ वस्तुओं के कमजोर संदर्भों का एक नक्शा रखेंगे और कॉलबैक चलाने के लिए सबसे हालिया संदर्भ (यदि उपलब्ध हो) प्राप्त करने के लिए कार्य कॉलबैक में एक खोज करेंगे। हालांकि हमारे दृष्टिकोण का मतलब एक एकल इकाई थी जो इस मानचित्रण को बनाए रखती थी, जबकि आपका दृष्टिकोण ऐसा नहीं है, इसलिए यह वास्तव में अच्छा है।
मथियास

1
क्या आपके पास रोबोस्पाइस पर एक नज़र है? github.com/octo-online/robospice । मेरा मानना ​​है कि यह प्रणाली और भी बेहतर है।
Snicolas

सामने पृष्ठ पर नमूना कोड ऐसा लगता है जैसे यह एक संदर्भ संदर्भ लीक कर रहा है (एक आंतरिक वर्ग बाहरी वर्ग के लिए एक अंतर्निहित संदर्भ रखता है।) आश्वस्त है !!
मथियास

@ मैथियास, आप सही कह रहे हैं, इसीलिए मैं एक स्थिर आंतरिक वर्ग का प्रस्ताव करता हूं जो गतिविधि पर एक कमजोर संदर्भ रखेगा।
स्निकोलस

1
@ मैथियास, मेरा मानना ​​है कि यह ऑफ टॉपिक है। लेकिन लोडर बॉक्स से बाहर कैशिंग प्रदान नहीं करते हैं जैसा कि हम करते हैं, अधिक से अधिक, लोडर हमारे कार्य की तुलना में अधिक क्रियाशील होते हैं। वास्तव में वे बहुत अच्छी तरह से कर्सर को संभालते हैं लेकिन नेटवर्किंग के लिए, कैशिंग और एक सेवा के आधार पर एक अलग दृष्टिकोण, बेहतर अनुकूल है। देखें neilgoodman.net/2011/12/26/... भाग 1 और 2
Snicolas

1

क्यों नहीं खुद की onPause()गतिविधि में विधि को ओवरराइड करें और AsyncTaskवहां से रद्द करें ?


यह उस कार्य पर निर्भर करता है। अगर यह सिर्फ कुछ डेटा लोड / पढ़ता है, तो यह ठीक होगा। लेकिन अगर यह रिमोट सर्वर पर कुछ डेटा की स्थिति को बदलता है तो हम कार्य को अंत तक चलाने की क्षमता देना पसंद करेंगे।
विट खूदेंको

@ अहित और मैं इसे लेता हूं यदि आप यूआई थ्रेड onPauseको पकड़ते हैं तो यह उतना ही बुरा है जितना कि इसे कहीं और पकड़ना? यानी, आपको एएनआर मिल सकता है?
जेफ एक्सिलरोड

बिल्कुल सही। हम UI थ्रेड को ब्लॉक नहीं कर सकते हैं (क्योंकि यह एक onPauseया एंथिंग है) क्योंकि हम एक ANR प्राप्त करने का जोखिम उठाते हैं।
विट खूदेंको

1

आप बिल्कुल सही हैं - यही कारण है कि डेटा लाने के लिए गतिविधियों में async कार्य / लोडर का उपयोग करने से दूर एक आंदोलन गति प्राप्त कर रहा है। नए तरीकों में से एक वॉली फ्रेमवर्क का उपयोग करना है जो डेटा तैयार होने के बाद अनिवार्य रूप से कॉलबैक प्रदान करता है - एमवीसी मॉडल के साथ अधिक सुसंगत। वॉली को Google I / O 2013 में आबादी दी गई थी। निश्चित रूप से अधिक लोगों को इसके बारे में पता नहीं है।


इसके लिए धन्यवाद ... मैं इसे देखने जा रहा हूं ... AsyncTask को पसंद नहीं करने का मेरा कारण यह है कि यह मुझे onPostExecute के निर्देशों के एक सेट के साथ अटका देता है ... जब तक कि मैं इसे हैक नहीं करता हूं या हर बार इसे ओवरराइड करना पसंद करता हूं मुझे जरूरत पडता है।
कारिनलिनचिन

0

व्यक्तिगत रूप से, मैं केवल थ्रेड का विस्तार करता हूं और UI को अपडेट करने के लिए कॉलबैक इंटरफ़ेस का उपयोग करता हूं। मैं एफसी मुद्दों के बिना सही काम करने के लिए एसिंस्कटस्क कभी नहीं प्राप्त कर सका। मैं निष्पादन पूल को प्रबंधित करने के लिए एक गैर अवरुद्ध कतार का भी उपयोग करता हूं।


1
ठीक है, आपके बल के पास संभवतः मेरे द्वारा बताई गई समस्या के कारण था: आपने एक संदर्भ का संदर्भ देने की कोशिश की, जो कि दायरे से बाहर हो गया था (अर्थात इसकी खिड़की नष्ट हो गई थी), जिसके परिणामस्वरूप एक फ्रेमवर्क अपवाद होगा।
Matthias

नहीं ... वास्तव में यह था क्योंकि कतार बेकार है जो AsyncTask में बनाया गया है। मैं हमेशा getApplicationContext () का उपयोग करता हूं। मुझे AsyncTask से कोई समस्या नहीं है यदि यह केवल कुछ ही ऑपरेशन है ... लेकिन मैं एक मीडिया प्लेयर लिख रहा हूं जो बैकग्राउंड में एल्बम आर्ट को अपडेट करता है ... मेरे टेस्ट में मेरे पास 120 एल्बम हैं जिनमें कोई आर्ट नहीं है ... इसलिए, जबकि मेरे ऐप ने सभी तरह से बंद नहीं किया, एसिंक्टस्क त्रुटियां फेंक रहा था ... इसलिए इसके बजाय मैंने एक कतार के साथ एक सिंगलटन क्लास बनाया जो प्रक्रियाओं का प्रबंधन करता है और अब तक यह बहुत अच्छा काम करता है।
androidworkz

0

मैंने सोचा कि काम रद्द कर देता है, लेकिन ऐसा नहीं है।

यहाँ वे इसके बारे में RTFMing कर रहे हैं:

"" यदि कार्य पहले ही शुरू हो चुका है, तो mayInterruptIfRunning पैरामीटर निर्धारित करता है कि इस कार्य को निष्पादित करने वाले थ्रेड को कार्य को रोकने के प्रयास में बाधित किया जाना चाहिए या नहीं। "

हालांकि, इसका मतलब यह नहीं है कि धागा बाधित है। यह एक जावा बात है, एक AsyncTask बात नहीं है। "

http://groups.google.com/group/android-developers/browse_thread/thread/dcadb1bc7705f1bb/add136eb4949359d?show_docid=add136eb4949359d


0

आप AsyncTask के बारे में सोचना बेहतर होगा क्योंकि एक गतिविधि, संदर्भ, संदर्भदाता, आदि के साथ अधिक कसकर युग्मित किया जाता है। यह एक सुविधा से अधिक है जब इसका दायरा पूरी तरह से समझा जाता है।

सुनिश्चित करें कि आपके पास अपने जीवनचक्र में एक रद्द करने की नीति है ताकि यह अंततः कचरा एकत्र हो जाए और अब आपकी गतिविधि का संदर्भ न हो और यह कचरा एकत्र भी हो सके।

अपने प्रसंग से दूर रहते हुए अपने AsyncTask को रद्द किए बिना आप मेमोरी लीक्स और NullPointerException में चलेंगे, अगर आपको बस Toast को एक साधारण संवाद की तरह फीडबैक प्रदान करना है तो आपके एप्लिकेशन कॉन्सेप्ट का एक सिंगलटन NPE समस्या से बचने में मदद करेगा।

AsyncTask सब बुरा नहीं है, लेकिन निश्चित रूप से बहुत सारा जादू चल रहा है जिससे कुछ अप्रत्याशित नुकसान हो सकते हैं।


-1

जैसा कि "इसके साथ काम करने के अनुभव": सभी AsyncTasks के साथ प्रक्रिया को मारना संभव है , एंड्रॉइड गतिविधि स्टैक को फिर से बनाएगा ताकि उपयोगकर्ता कुछ भी उल्लेख नहीं करेगा।

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