0

FATAL EXCEPTION: main Process: com.example.myapplication, PID: 3494 java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.

#Kotlin #Android
Rádrick Gomes
Rádrick Gomes

Em geral as aplicações necessitam de um banco de dados para persistir os dados. Essa persistência tem como base as ações denominadas como CRUD (Create, Read, Update e Delete).


As funções CRUD são desenvolvidas dentro de uma classe que possui acesso ao banco de dados e que faz o intermédio com o resto da aplicação.


Antes de abordamos o erro em si, é necessário entender um pouco sobre o que é o Cursor.


O Cursor é uma estrutura de controle que percorre os registros dentro de um banco de dados. O que facilita o processamento subsequente em conjunto de dados.


Imagine que o esquema a baixo seja uma tabela de clientes dentro de um banco de dados e você deseja recuperar os dados dos clientes.

ID Cód Nome

1 - x1 001 José

2 - x2 002 Maria

3 - x3 003 Steven

Com a implementação do cursor os registros vão ser lidos LINHA a LINHA e retornados posteriormente. Ou seja, o cursor vai iterar na primeira linha, logo em seguida na segunda linha e posteriormente na terceira linha. Caso necessite de alguma coluna específica, basta informar quais colunas deseja retornar.


Logo, com a utilização do cursor não é necessário desenvolver toda uma lógica que faça um loop nas linhas da tabela e retorne os valores.


A partir disso, esse artigo visa mostrar uma possível solução para um FATAL EXCEPTION referente ao Cursor na função de leitura (Read).


O erro apresentado no build do app é:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myapplication, PID: 3494
    java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
        at android.database.CursorWindow.nativeGetLong(Native Method)
        at android.database.CursorWindow.getLong(CursorWindow.java:553)
        at android.database.CursorWindow.getInt(CursorWindow.java:620)
        at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:71)
        at com.example.myapplication.service.db.GuestRepository.getAbsent(GuestRepository.kt:216)
        at com.example.myapplication.viewmodel.ViewModel.load(ViewModel.kt:26)
        at com.example.myapplication.view.AbsentsFragment.onResume(AbsentsFragment.kt:75)
        at androidx.fragment.app.Fragment.performResume(Fragment.java:2747)
        at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:373)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2007)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8425)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:596)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)


Não vou apresentar todo o código da classe que faz as funções CRUD para não confundir. Mas vou mostrar o código da função que busca informações com uma condição.


fun buscaAusentes(): List<GuestModel> {
    val lista: MutableList<GuestModel> = ArrayList()

        // conexão com o banco de dados
        val db = mDataBaseHelper.readableDatabase

        // define quais colunas o cursor vai retornar
        val colunas = arrayOf(NAME, CONFIRMATION)

        /* define qual a condição. Ou seja, retorna todas as linhas 
        *  que possuem a coluna CONFIRMATION igual a 0
        */
        val condicao = CONFIRMATION + " = 0 "

        // atribui a um cursor a consulta que deseja realizar no bd
        val cursor = db.query(TABLE_CONVIDADOS,
                colunas,
                condicao,
                null,
                null,
                null,
                null)

        // valida se o cursor é null
        if (cursor != null && cursor.count > 0) {

            //faz o loop no cursor enquanto retornar true
            while (cursor.moveToNext()) {

        //atribui as variáveis os valores das colunas
                val id = cursor.getInt(cursor.getColumnIndex(ID))
                val nome = cursor.getString(cursor.getColumnIndex(NAME))
                val confirmacao = (cursor.getInt(cursor.getColumnIndex(CONFIRMATION)) == 1)

              //adiciona o valores da coluna ao model
                val convidado = GuestModel(id, nome, confirmacao)
                lista.add(convidado)

            }
        }
        cursor?.close()
        db.close()
        return lista
}


O código acima mostra uma leitura (Read) de dados na tabela de convidados e retorna as linhas da tabela com duas colunas. Isso é definido em:


        // define quais colunas o cursor vai retornar
        val colunas = arrayOf(NAME, CONFIRMATION)

        /* define qual a condição. Ou seja, retorna todas as linhas 
        *  que possuem a coluna CONFIRMATION igual a 0
        */
        val condicao = CONFIRMATION + " = 0 "

        // atribui a um cursor a consulta que deseja realizar no bd
        val cursor = db.query(TABLE_CONVIDADOS,
                colunas,
                condicao,
                null,
                null,
                null,
                null)


Ou seja, a consulta ficou da seguinte forma: selecione na tabela TABLE_CONVIDADOS as colunas NAME, CONFIRMATION quando CONFIRMATION = 0


Logo em seguida, é atribuído as variáveis id, nome e confirmacao o retorno de cada linha com o método getColumnIndex.

Ficou da seguinte forma:


//atribui as variáveis os valores das colunas
                val id = cursor.getInt(cursor.getColumnIndex(ID))
                val nome = cursor.getString(cursor.getColumnIndex(NAME))
                val confirmacao = (cursor.getInt(cursor.getColumnIndex(CONFIRMATION)) == 1)


O ERRO acontece nesse exato momento. Pois, definimos na consulta o retorno de DUAS colunas (nome e confirmacao), e na atribuição das variáveis estamos definindo o retorno de TRÊS colunas (id, nome e confirmacao).


Com isso o cursor não consegue retornar os valores corretos para as variáveis e apresenta a EXCEPTION.


Uma possível solução para essa EXCEPTION é a inclusão de mais uma coluna na consulta, ou seja, no trecho de código que informa quais colunas retornar, deve-se incluir a coluna do ID.

Então ficaria assim:

// define quais colunas o cursor vai retornar
        val colunas = arrayOf(ID,NAME, CONFIRMATION)


Ou poderia remover da atribuição das variáveis o id. Ficaria da seguinte forma:

//atribui as variáveis os valores das colunas
                val nome = cursor.getString(cursor.getColumnIndex(NAME))
                val confirmacao = (cursor.getInt(cursor.getColumnIndex(CONFIRMATION)) == 1)


E uma terceira forma seria incluir o código dentro de um tratamento de exceção. Com isso, o aplicativo vai funcionar, mas vai retornar uma lista vazia. Ficaria da seguinte forma.


fun buscaAusentes(): List<GuestModel> {
    val lista: MutableList<GuestModel> = ArrayList()

    return try{
        // conexão com o banco de dados
        val db = mDataBaseHelper.readableDatabase

        // define quais colunas o cursor vai retornar
        val colunas = arrayOf(NAME, CONFIRMATION)

        /* define qual a condição. Ou seja, retorna todas as linhas 
        *  que possuem a coluna CONFIRMATION igual a 0
        */
        val condicao = CONFIRMATION + " = 0 "

        // atribui a um cursor a consulta que deseja realizar no bd
        val cursor = db.query(TABLE_CONVIDADOS,
                colunas,
                condicao,
                null,
                null,
                null,
                null)

        // valida se o cursor é null
        if (cursor != null && cursor.count > 0) {

        //faz o loop no cursor enquanto retornar true
        while (cursor.moveToNext()) {

                //atribui as variáveis os valores das colunas
                val id = cursor.getInt(cursor.getColumnIndex(ID))
                val nome = cursor.getString(cursor.getColumnIndex(NAME))
                val confirmacao = (cursor.getInt(cursor.getColumnIndex(CONFIRMATION)) == 1)

              //adiciona o valores da coluna ao model
                val convidado = GuestModel(id, nome, confirmacao)
                lista.add(convidado)
            }
        }
        cursor?.close()
        db.close()
        lista
    } catch (e: Exception) {
        lista
    }
}
0
7

Comentários (0)

Fortaleza - CE

Brasil