2010-04-25 20 views
8

मैं एक एडलेप्टर में एक अंतर्निहित सूची अद्यतन करने वाला एक IllegalStateException में चल रहा हूं (एक ऐरेएडाप्टर या बेसएडाप्टर का विस्तार हो सकता है, मुझे याद नहीं है)। मेरे पास इस समय अपवाद के पाठ को याद या याद नहीं है, लेकिन यह एडाप्टर को परिवर्तन के अधिसूचित किए बिना सूची की सामग्री के प्रभाव के प्रभाव में कुछ कहता है।एडाप्टर के अंतर्निहित डेटा को अपडेट करने का सबसे अच्छा तरीका क्या है?

यह सूची/UI थ्रेड (मुख्य) के अलावा किसी अन्य थ्रेड से अपडेट की जा सकती है। इस सूची को अपडेट करने के बाद (एक आइटम जोड़ना), मैं अधिसूचना कॉल करता हूंडेटासेट चेंज। समस्या यह प्रतीत होती है कि एडाप्टर से जुड़ा एडाप्टर, या ListView इस विधि को लागू करने से पहले खुद को अपडेट करने का प्रयास करता है। जब ऐसा होता है, तो IllegalStateException फेंक दिया जाता है।

यदि मैं अद्यतन से पहले सूची देखने के लिए सूची दृश्य दृश्यता सेट करता हूं, तो फिर से विज़िबल करें, कोई त्रुटि नहीं होती है। लेकिन यह हमेशा व्यावहारिक नहीं है।

मैंने कहीं पढ़ा है कि आप इसे किसी अन्य धागे से अंतर्निहित संशोधित नहीं कर सकते हैं - यह एक विशेष एमवीसी पैटर्न को सीमित करने के लिए प्रतीत होता है, जैसा कि इस विशेष सूची के साथ, मैं विभिन्न धागे से आइटम जोड़ना चाहता हूं। मैंने माना कि जब तक मैंने अधिसूचित किया हैडेटाट चेंज() मैं सुरक्षित रहूंगा - कि एडाप्टर ने अंतर्निहित सूची पर फिर से विचार नहीं किया जब तक कि इस विधि को लागू नहीं किया गया था लेकिन ऐसा लगता है कि यह मामला नहीं है।

मुझे लगता है कि मैं जो पूछ रहा हूं वह है, क्या यूआई के अलावा अन्य धागे से अंतर्निहित सूची को अपडेट करना सुरक्षित हो सकता है? इसके अतिरिक्त, अगर मैं एडाप्टर के भीतर डेटा को संशोधित करना चाहता हूं, तो क्या मैं अंतर्निहित सूची या एडाप्टर को संशोधित करता हूं (इसके ऐड(), आदि विधियों के माध्यम से)। एडाप्टर के माध्यम से डेटा को संशोधित करना गलत लगता है।

मैं किसी अन्य साइट पर एक थ्रेड में आया जो मेरे लिए एक जैसी समस्या है: http://osdir.com/ml/Android-Developers/2010-04/msg01199.html (यह वह जगह है जहां से मैंने दृश्यता को पकड़ लिया। और एक दृश्य विचार)।

आपको मेरी विशेष समस्या का बेहतर विचार देने के लिए, मैं कुछ बताऊंगा कि मेरी सूची, एडाप्टर इत्यादि कैसे स्थापित की गई हैं।

मेरे पास क्यू नामक एक ऑब्जेक्ट है जिसमें एक लिंक्डलिस्ट है। कतार पर्यवेक्षण का विस्तार करती है, और जब चीजों को अपनी विधियों के माध्यम से अपनी आंतरिक सूची में जोड़ा जाता है, तो मैं setChanged() और अधिसूचनासूची() को कॉल करता हूं। इस कतार वस्तु में किसी भी धागे से आइटम जोड़े या हटाए जा सकते हैं।

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

मैंने बहुत सारे लॉग आउटपुट को जोड़ा और यह निर्धारित किया कि जब यह IllegalStateExcption तब होता है जब मेरा ऑब्जर्वर कॉलबैक कभी नहीं लगाया जाता था। तो ऐसा लगता है कि एडाप्टर ने ऑब्जर्वर को अपने पर्यवेक्षकों को सूचित करने का मौका देने से पहले सूची के परिवर्तन को देखा, और एडाप्टर को सूचित करने के लिए मेरी विधि को कॉल किया कि सामग्री बदल गई है।

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

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

उत्तर

8

इस सूची// से यूआई धागा (मुख्य)

कि काम नहीं करेगा के अलावा अन्य एक और धागा अद्यतन किया जा सकता।

मैंने कहीं पढ़ा है आप से दूसरे धागा इस अंतर्निहित संशोधित नहीं कर सकते कि - इस सीमा एक MVC पैटर्न के लिए प्रतीत होता है, इस विशेष सूची के साथ के रूप में, मैं अलग धागे

से आइटम जोड़ना चाहते हैं

एमवीसी के धागे से कोई लेना देना नहीं है।

यह अन्य यूआई से धागे से अंतर्निहित सूची अद्यतन करने के लिए सुरक्षित हो सकता है?

सं अन्य सूत्र (post() के माध्यम से, उदाहरण के लिए) एडाप्टर के लिए अद्यतन ट्रिगर कर सकते हैं, लेकिन अद्यतन खुद को मुख्य आवेदन धागे पर संसाधित किया जाना चाहिए एक एडाप्टर है कि वर्तमान में एक ListView से जुड़ा हुआ है के लिए,।

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

आप अपने Adapter खुद के माध्यम से AdapterArrayAdapter के लिए संशोधित। CursorAdapter के लिए अंतर्निहित डेटाबेस/सामग्री प्रदाता के माध्यम से आप अपने Adapter को संशोधित करते हैं। अन्य एडाप्टर भिन्न हो सकते हैं।

मैंने किसी चीज़ कतार नामित कि एक LinkedList शामिल है। कतार व्यर्थ है, और जब अपनी विधियों के माध्यम से अपनी आंतरिक सूची में जोड़े जाते हैं, तो मैं setChanged() और अधिसूचनासूची() को कॉल करता हूं।

आप LinkedBlockingQueue का उपयोग कर के बजाय लागू करने पर विचार किया है अपने स्वयं के धागे की सुरक्षित Queue?

इस गतिविधि, अपने OnCreate() विधि में, मेरे कतार वस्तु के लिए एक पर्यवेक्षक श्रोता पंजीकृत करता है। ऑब्जर्वर की अपडेट() विधि में मैं एडाप्टर परडेटाडेट चेंज() को सूचित करता हूं।

Adapters स्वयं पर notifyDataSetChanged() बुलाना चाहिए (यदि परिवर्तन उनके द्वारा किया जाता है) या यह इकाई है कि डेटा से बदल रहा है द्वारा उन पर कहा जाता है (जैसे, एक CursorAdapter के लिए एक Cursor)। कि एमवीसी है। Activity को न तो पता होना चाहिए और न ही आपका डेटा मॉडल बदलना चाहिए।

तो यह रूप में अगर एडाप्टर सूची के परिवर्तन देखा से पहले पर्यवेक्षक था अपने पर्यवेक्षकों को सूचित करने के लिए, और एडाप्टर कि सामग्री बदल गया था सूचित करने के लिए मेरी विधि कॉल के लिए एक मौका है।

शायद आप एक ArrayAdapter, जिस स्थिति में इस अतिरिक्त पर्यवेक्षक/सूचित सामान अपने रास्ते में हो रही है, के बाद से है कि आप के लिए संभाला है प्रयोग कर रहे हैं। आपको मुख्य अनुप्रयोग धागे पर ArrayAdapter को अपडेट करने की व्यवस्था करने की आवश्यकता है।

तो मुझे लगता है कि मैं जो पूछ रहा हूं वह है यह एडाप्टर को रिग-अप करने का एक अच्छा तरीका है?

विशेष रूप से, IMHO नहीं।

इस क्योंकि मैं एक धागा यूआई धागा के अलावा अन्य से एडाप्टर के सामग्री को अपडेट कर रहा हूँ एक समस्या है?

यदि आप मुख्य एप्लिकेशन थ्रेड पर अपडेट को मजबूर नहीं कर रहे हैं, तो अंततः आप अपनी अन्य समस्याओं को साफ़ करने के बाद यह क्रैश हो जाएंगे।

देना कतार यूआई धागा कब बनाया जाता है करने के लिए हैंडलर ऑब्जेक्ट, और का उपयोग कर कि हैंडलर सभी सूची संशोधन करने, लेकिन यह अनुचित लगता है

आप एक Handler इस्तेमाल कर सकते हैं, या आप आपके संलग्न ListView पर post() पर कॉल कर सकता है।

कफ के बाहर, मैं ArrayAdapter का उप-वर्ग ThreadSafeArrayAdapter नामित करता हूं और इसे Queue के स्थान पर उपयोग करता हूं। ThreadSafeArrayAdapteradd(), insert(), और remove() को प्रतिस्थापित करता है जिनके साथ सुपरक्लास मुख्य अनुप्रयोग थ्रेड पर Handler या post() के माध्यम से अपनी चीज करता है।

+0

आपकी टिप्पणियों के लिए धन्यवाद, लेकिन अगर आप आगे की मदद नहीं करेंगे तो मैं कुछ चीजों पर उलझन में हूं। "कतार" ऑब्जेक्ट नाम एक गलत नामक है - यह वीडियो चलाने के लिए मीडिया की कतार है, या खेलने के लिए गाने है। यह एक मौजूदा इंडेक्स int के साथ आइटम की एक सूची है। मैं एडाप्टर को अपने मॉडल (मेरी सूची) के बीच सिर्फ एक पुल होने और देखने (ListView) के रूप में समझ गया। क्या होगा यदि मुझे उस डेटा को अपडेट करने की आवश्यकता है जो दृश्य किसी अन्य गतिविधि से प्रदर्शित होता है जहां मेरे पास एडाप्टर तक पहुंच नहीं है? अंतर्निहित सूची को अद्यतन करना स्वाभाविक प्रतीत होता है, शायद एक रननेबल से यदि यह कार्य करने वाला कार्य ब्लॉक हो सकता है। – skyler

+0

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

+0

लेकिन, आप इसे लागू करने के लिए स्वागत करते हैं, हालांकि आप चाहते हैं, जब तक आप केवल मुख्य एप्लिकेशन थ्रेड पर एडाप्टर अपडेट करें। – CommonsWare

0

कुल मिलाकर अच्छी सलाह http://developer.android.com/resources/articles/painless-threading.html

निजी तौर पर मैं अपने कस्टम धागा (एक वर्ग का विस्तार धागा) का उपयोग, लेकिन एक संदेश के माध्यम से यूआई धागा को जवाब भेजें है। धागा की दौड़() फ़ंक्शन में तो वहाँ है:

Message msg; 
msg = Message.obtain(); 
msg.what = MSG_IMG_SET;      
mExtHandler.sendMessage(msg); 

mExtHandler धागा निर्माता में बाहरी हैंडलर उदाहरण को सौंपा गया था।

private Handler mImagesProgressHandler; 

public void onCreate(Bundle bundle) { 

    mImagesProgressHandler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     switch (msg.what) {    
     case LoadImagesThread.MSG_IMG_SET: 
      mArrayAdapter.setBitmapList(mImagesList); 
      mArrayAdapter.notifyDataSetChanged(); 
      break; 
     case LoadImagesThread.MSG_ERROR: 
      break; 
     } 
     super.handleMessage(msg); 
    } 
};     

यह वास्तव में AsyncTask की तुलना में आसान है: यूआई धागा संदेश हैंडलर परिभाषित करता है।

+0

गैर स्थैतिक आंतरिक हैंडलर कक्षाओं से सावधान रहें। स्मृति रिसाव के लिए एक जोखिम हो सकता है। – HAxxor

+0

अच्छा बिंदु, धन्यवाद। – Yar

संबंधित मुद्दे