17

पर्यावरण requery करने की कोशिश करएंड्रॉयड त्रुटि: java.lang.IllegalStateException: (Xoom गोली के लिए लिनक्स/ग्रहण देव चल मधुकोश 3.0.1) एक पहले से ही बंद कर दिया कर्सर

मेरे ऐप मैं कैमरे का उपयोग कर रहा हूँ में (startIntentForResult ()) तस्वीर लेना। तस्वीर लेने के बाद मुझे एक्टिविटी रिसैट() कॉलबैक मिल गया है और "तस्वीर लेने" के माध्यम से पारित उरी का उपयोग करके बिटमैप लोड करने में सक्षम हूं। उस समय मेरी गतिविधि फिर से शुरू है और मैं एक गैलरी में छवियों को फिर से लोड करने की कोशिश कर कोई त्रुटि मिलती है:

FATAL EXCEPTION: main 
ERROR/AndroidRuntime(4148): java.lang.RuntimeException: Unable to resume activity {...}: 
java.lang.IllegalStateException: trying to requery an already closed cursor 
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2243) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1019) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:126) 
    at android.app.ActivityThread.main(ActivityThread.java:3997) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:491) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599) 
    at dalvik.system.NativeStart.main(Native Method) 
Caused by: java.lang.IllegalStateException: trying to requery an already closed cursor 
    at android.app.Activity.performRestart(Activity.java:4337) 
    at android.app.Activity.performResume(Activity.java:4360) 
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2205) 
    ... 10 more 

केवल कर्सर तर्क मैं उपयोग कर रहा हूँ है कि उसके बाद छवि लिया जाता है मैं एक फाइल करने के लिए उरी कन्वर्ट निम्नलिखित तर्क

String [] projection = { 
    MediaStore.Images.Media._ID, 
    MediaStore.Images.ImageColumns.ORIENTATION, 
    MediaStore.Images.Media.DATA 
}; 

Cursor cursor = activity.managedQuery( 
     uri, 
     projection, // Which columns to return 
     null,  // WHERE clause; which rows to return (all rows) 
     null,  // WHERE clause selection arguments (none) 
     null);  // Order-by clause (ascending by name) 

int fileColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
if (cursor.moveToFirst()) { 
    return new File(cursor.getString(fileColumnIndex)); 
} 
return null; 

कोई विचार क्या मैं गलत कर रहा हूं?

उत्तर

22

ऐसा लगता है कि प्रबंधितQuery() कॉल हनीकॉम एपीआई में बहिष्कृत है। managedQuery के लिए

डॉक्टर() पढ़ता है:

This method is deprecated. 
Use CursorLoader instead. 

Wrapper around query(android.net.Uri, String[], String, String[], String) 
that the resulting Cursor to call startManagingCursor(Cursor) so that the 
activity will manage its lifecycle for you. **If you are targeting HONEYCOMB 
or later, consider instead using LoaderManager instead, available via 
getLoaderManager()**. 

भी मैंने देखा है कि मैं cursor.close() क्वेरी जो मुझे लगता है कि बाद बुला रहा था नहीं-नहीं है। यह really helpful link भी मिला। कुछ पढ़ने के बाद मैं इस बदलाव के साथ आया जो काम करता प्रतीत होता है।

// causes problem with the cursor in Honeycomb 
Cursor cursor = activity.managedQuery( 
     uri, 
     projection, // Which columns to return 
     null,  // WHERE clause; which rows to return (all rows) 
     null,  // WHERE clause selection arguments (none) 
     null);  // Order-by clause (ascending by name) 

// ------------------------------------------------------------------- 

// works in Honeycomb 
String selection = null; 
String[] selectionArgs = null; 
String sortOrder = null; 

CursorLoader cursorLoader = new CursorLoader(
     activity, 
     uri, 
     projection, 
     selection, 
     selectionArgs, 
     sortOrder); 

Cursor cursor = cursorLoader.loadInBackground(); 
+0

आप हनीकोम्ब लक्षित कर रहे हैं विशेष रूप से। बस पाया कि मेरा Eclair + ऐप हनीकॉम्ब में टूटा हुआ है, प्रारंभ करने की वजह से कर्सर()। मेरा ऐप फोन पर लक्षित है, लेकिन आइसक्रीम सैंडविच बाहर आने पर नाराज ग्राहकों की प्रतीक्षा नहीं कर रहा है। – Tenfour04

+0

हां मैं विशेष रूप से हनीकॉम (टैबलेट) को लक्षित कर रहा हूं। –

+0

@ साइबर-भिक्षु हाय - मुझे कोई समस्या है। मैं इसे लागू नहीं कर सकता क्योंकि मेरा कोड कर्सर लोडर को पहचाना नहीं जाएगा। मैंने इसे सही तरीके से आयात किया लेकिन यह आयात को भी पहचान नहीं पाया। मैं यह कैसे तय करुं? – Mxyk

5

ठीक: context.getContentResolver().query बजाय activity.managedQuery का उपयोग करें।

Cursor cursor = null; 
try { 
    cursor = context.getContentResolver().query(uri, PROJECTION, null, null, null); 
} catch(Exception e) { 
    e.printStackTrace(); 
} 
return cursor; 
+0

मुझे एंड्रॉइड ओएस संस्करण 3.0 और उसके बाद के संस्करण पर एक ही समस्या का सामना करना पड़ रहा है, मैं ऐप को स्मार्टफोन और टैबलेट के लिए लक्षित कर रहा हूं। मैंने उपरोक्त सुझाए गए समाधानों को आजमाया, वे इस मुद्दे को हल नहीं कर पाए। अगर इस मुद्दे को हल करने के लिए हर किसी के पास कोई वैकल्पिक दृष्टिकोण है, तो कृपया इसे पोस्ट करें। – Rise

+0

@ रुपेश। मुझे लगता है कि आपने अभी तक अपनी समस्या हल कर ली है, लेकिन जब से आपने पूछा, मैंने अपना समाधान एक नए उत्तर में पोस्ट कर दिया है। उम्मीद है कि दूसरों को इससे फायदा होगा। –

7

रिकॉर्ड के लिए, यहाँ मैं अपने कोड (जो एंड्रॉयड 1.6 और ऊपर पर चलता है) में यह तय हो गई है: मेरे मामले में समस्या यह है कि मैं अनजाने CursorAdapter.changeCursor बुला द्वारा प्रबंधित कर्सर को बंद किया गया था()। के रूप में मैं पिछले जवाब (टिप्पणी किसी कारण से विकलांग) पर कोई टिप्पणी नहीं कर सकता

// changeCursor() will close current one for us: we must stop managing it first. 
Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); // *** adding these lines 
stopManagingCursor(currentCursor);           // *** solved the problem 
Cursor c = db.fetchItems(selectedDate); 
startManagingCursor(c); 
((SimpleCursorAdapter)getListAdapter()).changeCursor(c); 
3

मैं इस सवाल यहाँ बना लिया है: कॉलिंग Activity.stopManagingCursor() एडाप्टर के कर्सर पर कर्सर को बदलने से पहले समस्या हल हो। मैंने सोचा कि इस पर एक नया धागा खोलने से केवल जटिल चीजें ही होंगी।

मैं जब मैं गतिविधि एकको गतिविधि बी से जाना और फिर वापस गतिविधि एक के लिए जा रहा अनुप्रयोग क्रैश मिलता है। यह हर समय नहीं होता है - केवल कभी-कभी और मुझे यह पता चलने में मुश्किल होती है कि यह कहां होता है। सभी एक ही डिवाइस (नेक्सस एस) पर होते हैं लेकिन मुझे विश्वास नहीं है कि यह एक डिवाइस मुद्दा है।

मेरे पास @ मार्टिन स्टाइन के उत्तर के बारे में कुछ प्रश्न हैं।

  • प्रलेखन में यह changeCursor(c); के बारे में कहते हैं: "एक नया कर्सर करने के लिए अंतर्निहित कर्सर बदले कोई मौजूदा कर्सर यह बंद कर दिया जाएगा है।"। तो मुझे stopManagingCursor(currentCursor); - क्यों अनावश्यक नहीं है?
  • जब मैं @ मार्टिन स्टाइन द्वारा प्रदान किए गए कोड का उपयोग करता हूं तो मुझे एक शून्य सूचक अपवाद मिलता है। इसका कारण यह है कि आवेदन ((SimpleCursorAdapter)getListAdapter()) के पहले "रन" में एनयूएलएल का मूल्यांकन होगा क्योंकि कोई कर्सर अभी तक नहीं बनाया गया था।निश्चित रूप से मैं जांच सकता हूं कि मुझे शून्य नहीं मिल रहा है और केवल कर्सर को प्रबंधित करने के लिए रोकने का प्रयास करें, लेकिन आखिरकार मैंने अपना 'स्टॉप मैनेजिंग कर्सर (वर्तमान कर्सर) रखने का फैसला किया; इस गतिविधि के onPause() विधि में। मैंने सोचा कि इस तरह से मैं निश्चित रूप से एक कर्सर को प्रबंधन बंद करना होगा और मुझे गतिविधि को अलग-अलग छोड़ने से पहले इसे करना चाहिए। मुद्दा - मैं अपनी गतिविधि में कई कर्सर (एक संपादन टेक्स्ट फ़ील्ड का एक पाठ भरने के लिए और दूसरा एक सूची दृश्य के लिए) का उपयोग कर रहा हूं, मुझे लगता है कि उनमें से सभी एक सूची एडाप्टर कर्सर से संबंधित नहीं हैं -
    • मैं कैसे करूँ? पता है कि किसको प्रबंधन करना बंद करना है? अगर मेरे पास 3 अलग-अलग सूची दृश्य हैं?
    • क्या मुझे onPause() के दौरान उन सभी को बंद करना चाहिए?
    • मैं अपने सभी खुले कर्सर की सूची कैसे प्राप्त करूं?

तो कई सवाल ... आशा किसी को भी मदद कर सकता है।

जब मैं onPause() पर जाता हूं तो मेरे पास प्रबंधन रोकने के लिए एक कर्सर होता है लेकिन मुझे यह निर्धारित करने के लिए अभी भी पता नहीं है कि यह समस्या हल करती है क्योंकि यह त्रुटि स्पोरैडिक रूप से दिखाई देती है।

बहुत धन्यवाद!


कुछ जांच के बाद:

मुझे लगता है कि इस मुद्दे का "रहस्यमय" पक्ष का जवाब दे सकता है कुछ रोचक लगा:

गतिविधि एक दो कर्सर का उपयोग करता है: एक एक EditText को भरने के लिए खेत। दूसरा एक सूची दृश्य को पॉप्युलेट करना है।

गतिविधि ए से गतिविधि बी में जाने और वापस आने पर, गतिविधि ए में फ़ील्ड + सूची दृश्य फिर से भरा जाना चाहिए। ऐसा लगता है कि एडिटटेक्स्ट फ़ील्ड को इसके साथ कोई समस्या नहीं होगी। मुझे एडिटटेक्स्ट फ़ील्ड के वर्तमान कर्सर (Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); में) प्राप्त करने का कोई तरीका नहीं मिला, और कारण मुझे बताता है कि EditText फ़ील्ड इसे नहीं रखेगा। दूसरी तरफ ListView अपने कर्सर को आखिरी बार "गतिविधि ए -> गतिविधि बी से पहले" याद रखेगा। > गतिविधि एक और यह सब बिना मुझे कभी बुला

Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); 
stopManagingCursor(currentCursor); 

, जब सिस्टम की जरूरत है मैं कुछ मामलों में लगता है - इसके अलावा, और यह अजीब बात है, Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); गतिविधि बी के बाद एक अलग आईडी होगा संसाधनों को मुक्त करने के लिए, कर्सर को मार दिया जाएगा और जब गतिविधि बी -> गतिविधि ए, सिस्टम अभी भी इस पुराने मृत कर्सर का उपयोग करने का प्रयास करेगा, जिसके परिणामस्वरूप अपवाद होगा। और अन्य मामलों में प्रणाली एक नए कर्सर के साथ आ जाएगी जो अभी भी जीवित है और इस प्रकार कोई अपवाद नहीं होगा। यह समझा सकता है कि यह कभी-कभी क्यों दिखाई देता है। मुझे लगता है कि या तो एप्लिकेशन की गति के अंतर के कारण डीबग करना मुश्किल है या तो एप्लिकेशन चला रहा है या डीबग करना है। डिबगिंग करते समय, इसमें अधिक समय लगता है और इस प्रकार सिस्टम को नए कर्सर या इसके विपरीत आने का समय मिल सकता है।

मेरी समझ में यह

Cursor currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor(); 
stopManagingCursor(currentCursor); 

के उपयोग में आता है @Martin स्टाइन एक चाहिए कुछ मामलों में और अनावश्यक दूसरों में की सिफारिश के रूप में: अगर मैं विधि में लौटने और प्रणाली कोशिश कर रहा है एक मृत कर्सर का उपयोग करने के लिए, किसी को एक नया कर्सर बनाना होगा और उसे सूची एडाप्टर में बदलना होगा, अन्यथा मुझे क्रैश ऐप वाले क्रैश ऐप उपयोगकर्ता मिलेंगे।एक और मामले में जब सिस्टम खुद को एक नया कर्सर मिलेगा - उपर्युक्त पंक्तियां अनावश्यक हैं क्योंकि वे एक अच्छे कर्सर को अमान्य करते हैं और एक नया बनाते हैं।

मैं इस अतिरेक को रोकने के लिए लगता है कि मैं कुछ इस तरह की आवश्यकता होगी:

ListAdapter currentListAdapter = getListAdapter(); 
Cursor currentCursor = null; 
Cursor c = null; 

//prevent Exception in case the ListAdapter doesn't exist yet 
if(currentListAdapter != null) 
    { 
     currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor(); 

        //make sure cursor is really dead to prevent redundancy 
        if(currentCursor != null) 
        { 
         stopManagingCursor(currentCursor); 

         c = db.fetchItems(selectedDate); 

         ((SimpleCursorAdapter)getListAdapter()).changeCursor(c); 
        } 
        else 
        { 
         c = db.fetchItems(selectedDate); 

        } 
    } 
      else 
      { 
       c = db.fetchItems(selectedDate); 

      } 

startManagingCursor(c); 

मैं सुनने के लिए आप इस बारे में क्या सोचते प्यार होता!

0

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

मैं एक गतिविधि के जीवनकाल के लिए कर्सर खोलने के लिए उपयोग करता था लेकिन तब से मैंने इस लेनदेन के दृष्टिकोण के लिए त्याग दिया है। अब मेरा ऐप बहुत स्थिर है और "एंड्रॉइड त्रुटि: java.lang.IleglegalStateException: पहले से बंद कर्सर की आवश्यकता करने की कोशिश कर रहा है" से ग्रस्त नहीं है, भले ही वे एक ही डेटाबेस तक पहुंचते हैं।

static public Boolean musicReferencedByOtherFlash(NotesDB db, long rowIdImage) 
    { 
     Cursor dt = null; 
     try 
     { 
     dt = db.getNotesWithMusic(rowIdImage); 
     if ( (dt != null) 
      && (dt.getCount() > 1)) 
      return true; 
     } 
     finally 
     { 
     if (dt != null) 
      dt.close(); 
     } 
     return false; 
    } 
2

बस .. कर्सर ब्लॉक के अंत में निम्न कोड जोड़

try { 
       Cursor c = db.displayName(number); 

       startManagingCursor(c); 
       if (!c.moveToFirst()) { 
        if (logname == null) 
         logname = "Unknown"; 
        System.out.println("Null " + logname); 
       } else { 
        logname = c.getString(c 
          .getColumnIndex(DataBaseHandler.KEY_NAME)); 
        logdp = c.getBlob(c 
          .getColumnIndex(DataBaseHandler.KEY_IMAGE)); 
        // tvphoneno_oncall.setText(logname); 
        System.out.println("Move name " + logname); 
        System.out.println("Move number " + number); 
        System.out.println("Move dp " + logdp); 
       } 

       stopManagingCursor(c); 
      } 
+1

stopManagingCursor (सी); अंत में मेरे लिए काम किया! सरल! :) –

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