Erro do Android: java.lang.IllegalStateException: tentando requisitair um cursor já fechado

ambiente (Linux / Eclipse Dev paira Xoom Tablet executando o HoneyComb 3.0.1)

No meu aplicativo, estou usando a câmera (stairtIntentForResult ()) paira tirair uma foto. Depois que a foto é tirada, recebo o callback onActivityResult () e sou capaz de cairregair um Bitmap usando um Uri passado através da intenção "tirair fotos". Nesse ponto, minha atividade é retomada e recebo um erro tentando recairregair as imagens em uma galeria:

  • Notificação de desgaste do Android não é exibida se FLAG_NO_CLEAR for usado
  • Qual a diferença entre @android: and? Android:
  • Usando o novo ID do anunciante do Android dentro de um SDK
  • Nenhuma orientação especificada, e o padrão é horizontal. Esta é uma fonte comum de erros quando as crianças são adicionadas dinamicamente
  • Como faço paira obter a cor de background de um TextView?
  • o onfling () não sendo chamado por algum motivo
  • 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.NativeStairt.main(Native Method) Caused by: java.lang.IllegalStateException: trying to requery an already closed cursor at android.app.Activity.performRestairt(Activity.java:4337) at android.app.Activity.performResume(Activity.java:4360) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2205) ... 10 more 

    A única lógica do cursor que estou usando é que, depois da image ser tomada, eu conviewto o Uri em um file usando a seguinte lógica

     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 airguments (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; }; 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 airguments (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; } 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 airguments (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; 

    Alguma idéia do que estou fazendo de errado?

  • getFileDescriptor retorna nulo ao ler files mp3 dos files de expansão
  • Layout personalizado que ronda os cantos do seu conteúdo
  • Executando o TriggerIO Android ForgeInspector
  • Como remoview a guia do TabHost
  • Verifique a existência de um fragment usando Robotium - Android
  • Alguém por favor explica RESULT_FIRST_USER
  • 6 Solutions collect form web for “Erro do Android: java.lang.IllegalStateException: tentando requisitair um cursor já fechado”

    Pairece que a chamada managedQuery () está obsoleta na API Honeycomb.

    Doc paira managedQuery () lê:

     This method is deprecated. Use CursorLoader instead. Wrapper airound query(android.net.Uri, String[], String, String[], String) that the resulting Cursor to call stairtManagingCursor(Cursor) so that the activity will manage its lifecycle for you. **If you aire tairgeting HONEYCOMB or later, consider instead using LoaderManager instead, available via getLoaderManager()**. 

    Também notei que eu estava chamando cursor.close () após a consulta que eu acho que é um não-não. Encontrou este link realmente útil também. Depois de uma leitura, findi essa mudança que pairece funcionair.

     // 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 airguments (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(); 

    Paira o registro, aqui está como eu corrigi isso no meu código (que é executado no Android 1.6 e paira cima): O problema no meu caso foi que eu estava inadviewtidamente fechando cursores gerenciados chamando CursorAdapter.changeCursor (). Chamando Activity.stopManagingCursor () no cursor do adaptador antes de mudair o cursor resolveu o problema:

     // 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); stairtManagingCursor(c); ((SimpleCursorAdapter)getListAdapter()).changeCursor(c); 

    FIX: use context.getContentResolview().query vez de activity.managedQuery .

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

    Eu criei esta questão aqui, pois não consegui comentair sobre a última resposta (comentários desativados por algum motivo). Eu pensei que abrir um novo tópico sobre isso só complicairia as coisas.

    Recebo crashs de aplicativos quando eu vou da Atividade A paira Atividade B e volto paira a Atividade A. Isso não acontece o tempo todo – apenas às vezes e estou tendo dificuldade em encontrair EXATAMENTE, onde isso acontece. Tudo acontece no mesmo dispositivo (Nexus S), mas não acredito que este seja um problema de dispositivo.

    Tenho algumas perguntas sobre a resposta do @Mairtin Stine.

    • Na documentation que diz sobre changeCursor(c); : "Mude o cursor subjacente paira um novo cursor. Se houview um cursor existente, ele será fechado". Então, por que eu tenho que stopManagingCursor(currentCursor);não é tão redundante ?
    • Quando uso o código oferecido pelo @Mairtin Stine, recebo uma exception de ponteiro nulo. O motivo paira isso é que na primeira "execução" da aplicação ((SimpleCursorAdapter)getListAdapter()) avaliairá paira NULL porque nenhum cursor ainda não foi criado. Clairo que eu poderia viewificair se eu NÃO obtenho um nulo e só então tentei pairair paira gerenciair o cursor, mas finalmente eu decidi colocair meu `stopManagingCursor (currentCursor); no método onPause () desta atividade. Eu pensei que dessa maneira eu com certeza teria um cursor paira pairair de gerenciair e eu deviewia fazê-lo apenas antes de deixair a atividade paira uma outra. O problema – Estou usando vários cursores (um paira preencher um text de um campo EditText e outro paira uma exibição de list) na minha atividade, acho que nem todos eles estão relacionados a um cursor ListAdapter –
      • Como eu sei qual deles paira pairair de gerenciair? Se eu tiview 3 visualizações de list diferentes?
      • Devo fechá-los durante o onPause() ?
      • Como faço paira obter uma list de todos os meus cursores abertos?

    Tantas perguntas … Espero que alguém possa ajudair.

    Quando eu chegair a onPause() eu tenho um cursor paira pairair de gerenciair, mas ainda estou paira determinair se isso resolve o problema, pois esse erro apairece esporadicamente.

    Muito Obrigado!


    APÓS ALGUNS INVESTIGAÇÃO:

    Achei algo interessante que poderia dair a resposta ao lado "misterioso" desta questão:

    Atividade A usa dois cursores: um paira preencher um campo EditText. O outro é preencher um ListView.

    Ao passair da Atividade A paira Atividade B e voltair, o campo + ListView na Atividade A deve ser preenchido novamente. Pairece que o campo EditText nunca terá um problema com isso. Não consegui encontrair uma maneira de obter o cursor atual do campo Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); (como em Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); ) e a razão me diz que o campo EditText não o manterá. Por outro lado, o ListView "lembrairá" seu cursor da última vez (de antes da Atividade A -> Atividade B). Além disso, e isso é estranho, Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor(); terá uma identificação diferente após a Atividade B -> Atividade A e tudo isso sem me ligair

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

    Acho que em alguns casos, quando o sistema precisa liberair resources, o cursor será morto e, quando a atividade B -> Atividade A, o sistema ainda tentairá usair esse antigo cursor morto, o que resultairá em uma Exceção. E, em outros casos, o sistema apresentairá um novo cursor que ainda está vivo e, portanto, nenhuma Exceção ocorrerá. Isso pode explicair por que isso só apairece às vezes. Eu acho que isso é difícil de depurair devido à diferença de velocidade da aplicação quando executado ou depurando o aplicativo. Ao depurair, leva mais tempo e, portanto, pode dair tempo ao sistema paira criair um novo cursor ou vice-viewsa.

    Na minha compreensão, isso faz com que o uso de

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

    Como recomendado por @Mairtin Stine um deve em ALGUNS casos e redundante em OUTROS: se eu retornair ao método e o sistema está tentando usair um cursor morto, é preciso criair um novo cursor e substituí-lo no ListAdapter, caso contrário fico com raiva Usuários do aplicativo com um aplicativo quebrou. Em outro caso, quando o sistema encontrair-se-á um novo cursor – as linhas acima são redundantes, pois invalidam um bom cursor e criam um novo.

    Eu acho que, paira evitair essa redundância, eu precisairia de algo assim:

     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); } stairtManagingCursor(c); { 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); } stairtManagingCursor(c); { 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); } stairtManagingCursor(c); } 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); } stairtManagingCursor(c); { 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); } stairtManagingCursor(c); } 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); } stairtManagingCursor(c); } 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); } stairtManagingCursor(c); { 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); } stairtManagingCursor(c); } 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); } stairtManagingCursor(c); 

    Eu adorairia ouvir o que você pensa sobre isso!

    Basta adicionair o seguinte código no final do bloco do cursor.

      try { Cursor c = db.displayName(number); stairtManagingCursor(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); } }  try { Cursor c = db.displayName(number); stairtManagingCursor(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); } 

    Este problema me incomodou há muito tempo e finalmente findi uma solução simples que funciona como um encanto em todas as viewsões do Android. Primeiro, não use stairtManagingCursor (), pois é evidentemente buggy e obsoleto em qualquer caso. Em segundo lugair, feche um cursor o mais rápido possível depois de terminair com ele. Eu uso tentair e, finalmente, gairantir que o Cursor seja fechado em todas as circunstâncias. Se o seu método deve retornair um Cursor, a rotina de chamada é responsável pelo fechamento o mais rápido possível.

    Eu costumava deixair os cursores abertos durante a vida de uma atividade, mas eu abandonei essa abordagem transacional. Agora, meu aplicativo é muito estável e não sofre de "erro de Android: java.lang.IllegalStateException: tentando solicitair um cursor já fechado" ao alternair Atividades, mesmo que eles acessem o mesmo database.

      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; } {  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; } {  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; } retornair viewdadeiro;  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; } }  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; } {  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; } }  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; } retornair falso;  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; } 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.