Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

Erro após aulas

Olá, fiz as aulas e recebi alguns erros no console:

E/SQLiteLog: (20) statement aborts at 8: [UPDATE Alunos SET id=? WHERE id=?] datatype mismatch
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: br.com.alura.agenda, PID: 4630
                  java.lang.RuntimeException: Unable to resume activity {br.com.alura.agenda/br.com.alura.agenda.ListaAlunosActivity}: android.database.sqlite.SQLiteDatatypeMismatchException: datatype mismatch (code 20)
                      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3581)
                      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
                      at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4699)
                      at android.app.ActivityThread.-wrap18(Unknown Source:0)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595)
                      at android.os.Handler.dispatchMessage(Handler.java:106)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
                   Caused by: android.database.sqlite.SQLiteDatatypeMismatchException: datatype mismatch (code 20)
                      at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
                      at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:735)
                      at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
                      at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
                      at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1754)
                      at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1732)
                      at br.com.alura.agenda.dao.AlunoDAO$override.onUpgrade(AlunoDAO.java:71)
                      at br.com.alura.agenda.dao.AlunoDAO$override.access$dispatch(Unknown Source:68)
                      at br.com.alura.agenda.dao.AlunoDAO.onUpgrade(AlunoDAO.java:0)
                      at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:338)
                      at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:262)
                      at br.com.alura.agenda.dao.AlunoDAO$override.buscaAlunos(AlunoDAO.java:104)
                      at br.com.alura.agenda.dao.AlunoDAO$override.access$dispatch(Unknown Source:107)
                      at br.com.alura.agenda.dao.AlunoDAO.buscaAlunos(AlunoDAO.java:0)
                      at br.com.alura.agenda.ListaAlunosActivity.carregaLista(ListaAlunosActivity.java:62)
                      at br.com.alura.agenda.ListaAlunosActivity.onResume(ListaAlunosActivity.java:75)
                      at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1355)
                      at android.app.Activity.performResume(Activity.java:7107)
                      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3556)
                      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621) 
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862) 
                      at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4699) 
                      at android.app.ActivityThread.-wrap18(Unknown Source:0) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595) 
                      at android.os.Handler.dispatchMessage(Handler.java:106) 
                      at android.os.Looper.loop(Looper.java:164) 
                      at android.app.ActivityThread.main(ActivityThread.java:6494) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Por conta do número de caracteres vou colocar os códigos nas respostas, mas se alguém já souber o problema, fico grato!

11 respostas

AlunoDAO (somente partes alteradas):

public class AlunoDAO extends SQLiteOpenHelper {
    public AlunoDAO(Context context) {
        super(context, "Agenda", null, 4);
    }

onCreate...

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql;
        switch (oldVersion) {
            case 1:
                sql = "ALTER TABLE Alunos ADD COLUMN caminhoFoto TEXT";
                db.execSQL(sql);
            case 2:
                String criandoTabelaNova = "CREATE TABLE Alunos_novo " +
                        "(id CHAR(36) PRIMARY KEY," +
                        "nome TEXT NOT NULL, " +
                        "endereco TEXT, " +
                        "telefone TEXT, " +
                        "site TEXT, " +
                        "nota REAL, " +
                        "caminhoFoto TEXT);";
                db.execSQL(criandoTabelaNova);

                String inserindoAlunosNaTabelaNova = "INSERT INTO Alunos_novo " +
                        "(id, nome, endereco, telefone, site, nota, caminhoFoto) " +
                        "SELECT id, nome, endereco, telefone, site, nota, caminhoFoto FROM Alunos";
                db.execSQL(inserindoAlunosNaTabelaNova);

                String removendoTabelaAntiga = "DROP TABLE Alunos";
                db.execSQL(removendoTabelaAntiga);

                String alterandoNomeDaTabelaNova = "ALTER TABLE Alunos_novo RENAME TO Alunos";
                db.execSQL(alterandoNomeDaTabelaNova);
            case 3:
                String buscaAlunos = "SELECT * FROM Alunos";
                Cursor c = db.rawQuery(buscaAlunos, null);
                List<Aluno> alunos = populaAlunos(c);
                String atualizaIdDoAluno = "UPDATE Alunos SET id=? WHERE id=?";
                for (Aluno aluno: alunos) {
                    db.execSQL(atualizaIdDoAluno, new String[] {geraUUID(), aluno.getId()});
                }
                c.close();
        }
    }

    private String geraUUID() {
        return UUID.randomUUID().toString();
    }

    public void insere(Aluno aluno) {
        SQLiteDatabase db = getWritableDatabase();

        ContentValues dados = pegaDadosDoAluno(aluno);

        db.insert("Alunos", null, dados);
        //aluno.setId(id);
    }

    public List<Aluno> buscaAlunos() {
        String sql = "SELECT * FROM Alunos;";
        SQLiteDatabase db = getReadableDatabase();
        Cursor c = db.rawQuery(sql, null);

        List<Aluno> alunos = populaAlunos(c);
        c.close();
        return alunos;
    }

carregaLista():

private void carregaLista() {
        AlunoDAO dao = new AlunoDAO(this);
        List<Aluno> alunos = dao.buscaAlunos();
        for (Aluno aluno : alunos) {
            Log.i("id do aluno", String.valueOf(aluno.getId()));
        }
        dao.close();

        AlunosAdapter adapter = new AlunosAdapter(this, alunos);
        listaAlunos.setAdapter(adapter);
    }

Terminando, alterei também o atributo id de Aluno para String e acredito que mudei tudo que foi citado na aula, pois não há mais problemas que o Android Studio aponta. Esperando a resposta, e precisando de qualquer coisa é só pedir que eu envio!

Oi Gabriel, tudo bem?

Segundo o erro, o problema está no tipo de dado do id que está no banco, provavelmente ele não foi modificado para que suporte o UUID. Sendo assim, a minha sugestão é que verifique se a tabela do onCreate() esteja modificada para criar a tabela com id recebendo um CHAR(36), então, apague as informações da App ou a desinstale e instale novamente, e veja se funciona.

Lembrando que essa possibilidade é válida considerando que as informações estão no servidor, caso contrário seria uma má prática, pois você perderia as informações, ou seja, outra migration seria necessária.

Caso não funcionar, consegue me mandar o código via GitHub? Pois dessa forma eu consigo baixar, testar e enviar a sugestão de modificação.

[]s

Olá professor, apaguei as informações e tentei dnv, mas agora o erro é outro. Olhando no console, o que está acontecendo é o seguinte: Quando adiciono um aluno na lista, ele é salvo com id incremental, como estava antes. Na hora que eu clico no aluno e salvo ele novamente sem alterar nada, o UUID aparece e substitui o incremental. Abrindo no localhost, dá pra ver que os alunos foram salvos com id incremental, mas clicando em um deles para ver o formulário, o link fica como em http://localhost:8080/aluno/658a8afd-f0b6-4096-9b4b-229e3275d89e (começo da url/UUID do aluno)

Teria algum e-mail para eu poder te enviar o código no Google Drive? Meu Git está com problemas.

Obrigado pela ajuda

Opa Gabriel, me manda no alex.vieira@caelum.com.br. Assim que possível eu verifico e te mando um feedback.

Mandei lá, Alex. Vê se recebeu e avisa quando encontrar o erro!

Oi Gabriel, o seu projeto está sem o arquivo main que contém o src, res e o manifest, ou seja, preciso deles para poder analisar o código.

Oi professor, o upload não havia acabado, só percebi quando vi sua mensagem. Agora todos os arquivos estão lá, pode conferir :)

solução!

Oi Gabriel, vi aqui o código e identifiquei os pontos problemáticos.

Note que nos métodos que preenche e salva o usuário, você não insere o novo id (no caso o UUID) para o usuário, ou seja, por padrão o SQLite estava fazendo o papel dele de inserir de maneira incremental. Portanto, você vai precisar aplicar as seguintes alterações:

public void insere(Aluno aluno) {
    SQLiteDatabase db = getWritableDatabase();

    // gera o id no usuário antes de adicionar no objeto do tipo ContentValues
    String id = geraUUID();
    aluno.setId(id);

    ContentValues dados = pegaDadosDoAluno(aluno);

    db.insert("Alunos", null, dados);        
}

@NonNull
private ContentValues pegaDadosDoAluno(Aluno aluno) {
    ContentValues dados = new ContentValues();
    // adiciona o id dentro do ContentValues
    dados.put("id", aluno.getId());
    dados.put("nome", aluno.getNome());
    dados.put("endereco", aluno.getEndereco());
    dados.put("telefone", aluno.getTelefone());
    dados.put("site", aluno.getSite());
    dados.put("nota", aluno.getNota());
    dados.put("caminhoFoto", aluno.getCaminhoFoto());
    return dados;
}

Também, veja que no onCreate() você ainda manteve o id como INTEGER, ou seja, precisa modificar para CHAR(36) para quando remover as informações da app ou desinstalar, deixe o banco da mesma maneira como fez na migration. Então ele fica da seguinte maneira:

@Override
public void onCreate(SQLiteDatabase db) {
    // deixando o id da criação da tabela como CHAR(36)
    String sql = "CREATE TABLE Alunos (id CHAR(36) PRIMARY KEY, " +
            "nome TEXT NOT NULL, " +
            "endereco TEXT, " +
            "telefone TEXT, " +
            "site TEXT, " +
            "nota REAL, " +
            "caminhoFoto TEXT);";
    db.execSQL(sql);
}

Faça a modificação e veja se agora funciona.

[]s

Muito obrigado pela paciência e pela ajuda, Alex! Agora tudo está funcionando como o esperado, obrigado mesmo!!

[]s

Opa Gabriel, tendo dúvida e precisando de ajuda não exite :)

Bons estudos!