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

Aplicativo fecha ao tentar carregar alunos do servidor

Olá, boa tarde.

O meu aplicativo fecha quando abre a lista de alunos e ao tentar carregar os alunos o Monitor do Android Studio anuncia o seguinte erro:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.example.jefacb10.agenda, PID: 3541
                  java.lang.NullPointerException: println needs a message
                      at android.util.Log.println_native(Native Method)
                      at android.util.Log.e(Log.java:334)
                      at com.example.jefacb10.agenda.ListaAlunosActivity$5.onFailure(ListaAlunosActivity.java:210)
                      at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$2.run(ExecutorCallAdapterFactory.java:79)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:148)
                      at android.app.ActivityThread.main(ActivityThread.java:7406)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
I/Process: Sending signal. PID: 3541 SIG: 9
Application terminated.

Peço que me auxiliem, por gentileza, pois não poderei prosseguir nos outros cursos de Android com Web Service sem este aplicativo estar em funcionamento.

Obs.: O identificador do aluno que vocês usam como "id" no banco de dados eu utilizo como "numeroMatricula" e está desta forma em toda a programação. Caso houver alguma diferença, peço que me informem.

15 respostas

Oi Jeferson, tudo bem?

Pode me mandar o código da classe Aluno? Pois o erro está indicando no momento em que a requisição é realizada, veja que o onFailure está sendo chamado.

[]s

Olá, Alex, segue o código:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Aluno implements Serializable{

    private String numeroMatricula;
    private String nome;
    private String endereco;
    private String telefone;
    private String site;
    private Double nota;
    private String caminhoFoto;

    public String getNumeroMatricula() {
        return numeroMatricula;
    }

    public void setNumeroMatricula(String numeroMatricula) {
        this.numeroMatricula = numeroMatricula;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getEndereco() {
        return endereco;
    }

    public void setEndereco(String endereco) {
        this.endereco = endereco;
    }

    public String getTelefone() {
        return telefone;
    }

    public void setTelefone(String telefone) {
        this.telefone = telefone;
    }

    public String getSite() {
        return site;
    }

    public void setSite(String site) {
        this.site = site;
    }

    public Double getNota() {
        return nota;
    }

    public void setNota(Double nota) {
        this.nota = nota;
    }

    public String getCaminhoFoto() {
        return caminhoFoto;
    }

    public void setCaminhoFoto(String caminhoFoto) {
        this.caminhoFoto = caminhoFoto;
    }

    @Override
    public String toString() {
        return getNumeroMatricula()+ " - " + getNome();
    }
}

Oi Jeferson, tudo bem?

Para que você consiga pegar o valor do id que vem no JSON, você precisa utilizar a annotation @JsonProperty enviando o parâmetro "id":

@JsonProperty("id")
private String numeroMatricula;

Dessa forma, todas as vezes que esse valor for serializado ou deserializado ele vai ser nomeado como id.

Entretanto, provavelmente esse não é o problema do erro, pois você está utilizando a annotation @JsonIgnoreProperties(ignoreUnknown = true) que previne a exception quando não existe um campo esperado no JSON...

Sendo assim, pode me mandar o código que vc faz a requisição e chama o callback?

[]s

Olá, Alex. Tudo sim e você?

Segue o trecho da requisição feita na ListaAlunosActivity:

@Override
    protected void onResume() {
        super.onResume();

        //Pega os alunos do servidor o traz os dados em forma de lista
        Call<AlunoSync> call = new RetrofitInicializador().getAlunoService().lista();
        call.enqueue(new Callback<AlunoSync>() {
            @Override
            public void onResponse(Call<AlunoSync> call, Response<AlunoSync> response) {
                AlunoSync alunoSync = response.body();
                alunoDAO dao = new alunoDAO(ListaAlunosActivity.this);
                dao.sincroniza(alunoSync.getAlunos());
                dao.close();
                carregaAlunos();
            }

            @Override
            public void onFailure(Call<AlunoSync> call, Throwable t) {
                Log.e("onFailure chamado", t.getMessage());
            }
        });
        carregaAlunos();
    }

O seu callback está correto, não vejo nenhum problema...

Você consegue me enviar o seu projeto? Se possível via GitHub. Dessa forma, tenho a capacidade de testar o seu projeto e ver se existe algum ponto de falha que não estou conseguindo pegar apenas olhando no código.

Pois o erro apresentado, não diz muito do real problema que está acontecendo.

[]s

Boa tarde, Alex.

Segue o endereço do github com os arquivos do meu projeto: https://github.com/jefacb10/Agenda

Oi Jerferson, o módulo app não veio junto, pode adicioná-lo por favor?

Alex, o app.iml foi adicionado. Seria esse que estava faltando?

Oi Jeferson, me refiro ao diretório app onde tem o src do projeto, veja que ele não foi no push

Alex, boa noite.

Os arquivos dentro da pasta SRC foram adicionados. Se precisar de mais alguma coisa, me informe, por gentileza.

Oi Jerferson, blz? Eu identifiquei o detalhe que estava com problema, ou seja, precisa apenas colocar a annotation @JsonProperty("id") no atributo numeroMatricula, pois, dessa forma, será possível realizar o processo de deserialização:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Aluno implements Serializable {

    @JsonProperty("id")
    private String numeroMatricula;

    //restante do código
}

Apenas fiz essa modificação e funcionou tudo certinho.

Também existem outros pontos importantes que vi no código, como por exemplo, a sua classe que representa o DAO, atualmente ela está escrita como alunoDAO sendo que a convenção do Java é o CamalCase, ou seja, classes são escritas iniciando com letras maiúsculas.

Além disso, veja que no método onCreate do DAO, o campo numeroMatricula da tabela de alunos está com o tipo INTEGER sendo que agora lidamos com CHAR(36).

[]s

Olá, Alex. Fiz as alterações que você exigiu, menos do nome da classe DAO. Ao rodar o aplicativo ocorreu o seguinte erro:

D/OkHttp: {"alunos":[{"id":"92312d05-dfbc-48a6-87c0-bfbb92320d64","nome":"Jeferson ","endereco":"","telefone":"","site":"","nota":0.0,"desativado":0,"idCliente":0}],"momentoDaUltimaModificacao":"2017-10-04T18:24:18.476"} D/OkHttp: <-- END HTTP (210-byte body) I/aluno: [92312d05-dfbc-48a6-87c0-bfbb92320d64 - Jeferson ] E/SQLiteLog: (20) statement aborts at 5: [INSERT INTO tbAluno(caminhoFoto,nome,numeroMatricula,nota,endereco,site,telefone) VALUES (?,?,?,?,?,?,?)] datatype mismatch E/SQLiteDatabase: Error inserting caminhoFoto=null nome=Jeferson numeroMatricula=92312d05-dfbc-48a6-87c0-bfbb92320d64 nota=0.0 endereco= site= telefone= android.database.sqlite.SQLiteDatatypeMismatchException: datatype mismatch (code 20)

#

Error Code : 20 (SQLITE_MISMATCH) Caused By : Data type mismatch. (datatype mismatch (code 20))

#

at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:915) at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1626) at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1496) at com.example.jefacb10.agenda.dao.alunoDAO.insere(alunoDAO.java:105) at com.example.jefacb10.agenda.dao.alunoDAO.sincroniza(alunoDAO.java:182) at com.example.jefacb10.agenda.ListaAlunosActivity$5.onResponse(ListaAlunosActivity.java:203) at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) D/OkHttp: <-- HTTP FAILED: java.net.SocketTimeoutException E/onFailure: Requisicao falhou

Sabe do que se trata?

solução!

Oi Jeferson, o erro indica que teve um problema durante a inserção no banco de dados, a minha sugestão é que modifique o DAO como eu comentei e desinstale a instale novamente a App para que ele crie novamente o banco com as alterações do onCreate, claro, se quiser, pode consultar o código fonte que fiz no curso para o DAO, para verificar se tem alguma divergencia no que já foi implementado.

Repara que você está recebendo o objeto agora :)

Então é só corrigir o DAO mesmo.

Após desinstalar e instalar novamente as configurações deram certo. Agradeço muito sua ajuda, Alex.

Bem, final feliz! Legal a discussão.