35

मेरे पास एक ऐसा ऐप है जिसे सर्वर से डेटा खींचने और उपयोगकर्ता इनपुट के जवाब में SQLite डेटाबेस में डालने की आवश्यकता होती है। मैंने सोचा कि यह बहुत आसान होगा - सर्वर से डेटा खींचने वाला कोड AsyncTask का एक काफी सरल सबक्लास है, और यह ठीक उसी तरह काम करता है जैसा कि मैं यूआई थ्रेड को लटकाने के बिना उम्मीद करता हूं। मैं एक सरल अंतरफलक के साथ इसके लिए कॉलबैक कार्यक्षमता लागू और एक स्थिर वर्ग में लपेटा, तो मेरे कोड इस तरह दिखता है:ContentProvider insert() हमेशा यूआई थ्रेड पर चलता है?

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() { 
    @Override 
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) { 
     // do something with contents 
    } 
} 

सभी अभी भी अच्छा है। यहां तक ​​कि यदि सर्वर को डेटा पुनर्प्राप्त करने में एक घंटा लगते हैं, तो यूआई अभी भी सुचारू रूप से चलता है, क्योंकि कोड में फोल्डरकंट्स एक AsyncTask (जो यूआई से अलग थ्रेड में है) की doInBackground विधि में चल रहा है। GetFolderContents विधि के बहुत अंत में, ऑनफोल्डरकंट्स रेस्पॉन्स को सर्वर से प्राप्त फाइल सिस्टम एंट्री की सूची कहा जाता है और पास किया जाता है। मैं केवल इतना ही कहता हूं कि यह उम्मीद है कि मेरी समस्या getFolderContents विधि या मेरे किसी भी नेटवर्किंग कोड में नहीं है, क्योंकि यह कभी नहीं होती है।

समस्या तब उत्पन्न होती है जब मैं ContentProviderResponse विधि के भीतर ContentProvider के अपने उप-वर्ग के माध्यम से डेटाबेस में डालने का प्रयास करता हूं; UI हमेशा उस कोड को निष्पादित करते समय लटकता है, जिससे मुझे विश्वास होता है कि AsyncTask की doInBackground विधि से बुलाए जाने के बावजूद, इन्सर्ट अभी भी यूआई थ्रेड पर चल रहे हैं।

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() { 
    @Override 
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) { 
     insertContentsIntoDB(contents); 
    } 
} 

और insertContentsIntoDB विधि:: यहाँ समस्याग्रस्त कोड कैसा दिखता है

void insertContentsIntoDB(final List<FilesystemEntry> contents) { 
    for (FilesystemEntry entry : contents) { 
     ContentValues values = new ContentValues(); 
     values.put(COLUMN_1, entry.attr1); 
     values.put(COLUMN_2, entry.attr2); 
     // etc. 

     mContentResolver.insert(MyContentProvider.CONTENT_URI, values); 
    } 
} 

जहां mContentResolver पहले विधि getContentResolver() के परिणाम पर सेट किया गया है।

मैं अपनी ही थ्रेड में insertContentsIntoDB डाल, तो तरह की कोशिश की है:

MyServerCaller.getFolderContents(folderId, new OnFolderContentsResponseListener() { 
    @Override 
    public void onFolderContentsResponse(final List<FilesystemEntry> contents) { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       insertContentsIntoDB(contents); 
      } 
     }).run(); 
    } 
} 

मैं भी अपने स्वयं के सूत्र में प्रत्येक व्यक्ति डालने चल कोशिश की है (MyContentProvider में डालने विधि सिंक्रनाइज़ है, तो यह shouldn

void insertContentsIntoDB(final List<FilesystemEntry> contents) { 
    for (FilesystemEntry entry : contents) { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       ContentValues values = new ContentValues(); 
       values.put(COLUMN_1, entry.attr1); 
       values.put(COLUMN_2, entry.attr2); 
       // etc. 
       mContentResolver.insert(MyContentProvider.CONTENT_URI, values); 
      } 
     }).run(); 
    } 
} 

और बस अच्छा उपाय, मैं भी उन समाधानों के दोनों एक और AsyncTask की doInBackground विधि में प्रासंगिक कोड के साथ की कोशिश की है: 'टी वहाँ किसी भी मुद्दे) होता है। अंत में, मैं स्पष्ट रूप से मेरे AndroidManifest.xml में एक अलग प्रक्रिया में रहने वाले के रूप में परिभाषित किया है MyContentProvider:

<provider android:name=".MyContentProvider" android:process=":remote"/> 

यह ठीक चलाता है, लेकिन यह अभी भी यूआई धागा में चलाने के लिए लगता है। यही वह बिंदु है जहां मैंने वास्तव में इस पर अपने बालों को फाड़ना शुरू कर दिया, क्योंकि इससे मुझे कोई समझ नहीं आती है। कोई फर्क नहीं पड़ता कि मैं क्या करता हूं, यूआई हमेशा आवेषण के दौरान लटकता है। क्या उन्हें पाने के लिए कोई रास्ता नहीं है?

+0

अपनी परिकल्पना को सत्यापित करने के लिए अपने ContentProvider से वर्तमान थ्रेड आईडी/नाम प्रिंट करें। और/या डीबगर का उपयोग करें और चल रहे धागे की जांच करें। –

उत्तर

52

mContentResolver.insert() पर कॉल करने के बजाय, AsyncQueryHandler और इसकी startInsert() विधि का उपयोग करें।AsyncQueryHandler एसिंक्रोनस ContentResolver प्रश्नों को सुविधाजनक बनाने के लिए डिज़ाइन किया गया है।

+0

आपको बहुत बहुत धन्यवाद, यह वही करता है जो मैं ढूंढ रहा था! – jcsmnt0

+0

@ jcsmnt0 खुशी से यह मदद मिली :) –

+0

धन्यवाद! मैं अभी बहुत खुश हूं: डी – passsy

0

मैन। अपने आप को ठीक करें। और कुछ भी बेहतर दिखता है। सबसे पहले, एक थ्रेड प्रारंभ करें Func Func नहीं शुरू होता है, अगर आप नया थ्रेड प्रारंभ करना चाहते हैं तो न केवल func रन को कॉल करें।

new Thread(Runnable runnable).start(); 

तब मैं शर्त लगाता हूं कि हैंडलर कभी-कभी AsyncTask से बेहतर होगा।

+0

हैंडलर हमेशा अपने मूल धागे में चलता है और पृष्ठभूमि में नहीं चलता है। –

0

आप AsynTask पर ओवरराइड विधि में क्वेरी चला सकते हैं, और onPostExecute(Integer int) विधि पर मुख्य UI अपडेट कर सकते हैं।

3

मुझे लगता है कि आपकी मूल समस्या यह हो सकती है कि आप start विधि को कॉल करने के बजाय अपने नए धागे पर run विधि को कॉल कर रहे हैं (जो मौजूदा थ्रेड पर निष्पादन का कारण बनता है)। मुझे लगता है कि ब्राइट ग्रेट अपने जवाब में कहने की कोशिश कर रहा था। Difference between running and starting a thread देखें। यह एक आम गलती है।

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