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

Dúvida no Ex. 11 da Aula 5 - Persistência com SQLite

Fala turma me surgiu uma dúvida aqui bem diferente.

Por exemplo fechamos nossa DAO dentro da activity, mas existe alguma distinção entre fechar ela na activity ou fechar ela depois de realizar a inserção no banco, desta maneira:

ContentValues values = getContentValues(aluno);
        try {

            SQLiteDatabase db =  getWritableDatabase();
            db.insert(AlunoEs.TABELA + "", null, values);
            db.close();
        }catch (Exception e){
            throw new RuntimeException(e);
        }

Qual seria o processo ideal?

3 respostas

Olá Hermivaldo!

Quando colocamos o close dentro do próprio DAO, o que acontece se precisarmos fazer uma operação como a descrita abaixo:

AlunoDAO dao = new AlunoDAO(this);

dao.insere(alunos);
List<Aluno> alunos = dao.getAlunos();

Como o DAO foi fechado dentro do método insere(), quando tentamos fazer a segunda operação que é pegar a lista de alunos, teremos uma exception indicando o recurso que queremos acessar (banco de dados) já foi fechado.

Aí teríamos que fazer o seguinte para obter o resultado esperado:

AlunoDAO dao = new AlunoDAO(this);
dao.insere(alunos);

// Abre o DAO novamente para realizar a segunda operação
dao = new AlunoDAO(this);
List<Aluno> alunos = dao.getAlunos();

Agora, se deixamos o close() como responsabilidade de quem usa o DAO, podemos fazer todas as operações desejadas e no final invocar o close():

AlunoDAO dao = new AlunoDAO(this);

dao.insere(alunos);
List<Aluno> alunos = dao.getAlunos();

dao.close();

Abraço!

Olá Jeferson.

O que me disse faz bastante sentido, mas qual a grande questão que esqueci de destacar. Na minha DAO eu uso objetos diferentes, olhe meu código.

 public void inserirAluno(Aluno aluno){
        ContentValues values = getContentValues(aluno);
        try {

            SQLiteDatabase db =  getWritableDatabase();
            db.insert(AlunoEs.TABELA + "", null, values);
            db.close();
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

Agora olhe meu código de consulta.

public List<Aluno> getAllAlunos(){
        List<Aluno> alunos = new ArrayList<Aluno>();

        String dml = "SELECT * FROM " + AlunoEs.TABELA.toString();
        SQLiteDatabase db = getReadableDatabase();
        Cursor cursor = db.rawQuery(dml,null);

        while (cursor.moveToNext()){
            Aluno aluno = getAluno(cursor);
            alunos.add(aluno);
        }

        return alunos;
    }

Utilizo de objetos diferentes, isto não ocasiona nenhum problema para a aplicação. Mesmo executando as operações em seguida como chegou a mencionar:

 public void cadastrar(View view){

        Aluno aluno = new Aluno();
        aluno.setNome(((EditText) findViewById(R.id.nome)).getText().toString());
        aluno.setEndereco(((EditText) findViewById(R.id.endereco)).getText().toString());
        aluno.setTelefone(((EditText) findViewById(R.id.telefone)).getText().toString());
        aluno.setSite(((EditText) findViewById(R.id.site)).getText().toString());
        aluno.setNota(((RatingBar) findViewById(R.id.nota)).getRating());

        AlunoDAO dao =  new AlunoDAO(this);
        dao.inserirAluno(aluno);
        List<Aluno> alunos = dao.getAllAlunos();
        CustomAdapter adapter = new CustomAdapter(alunos,this);

        MainActivity.myList.setAdapter(adapter);
        onBackPressed();
    }

Acho que pode haver casos e acasos, porém a solução funciona e acho que funciona bem. Não conseguir fazer ela apresentar erros. Claro que se a rotina for mais elaborada, talvez o fechamento deva ser invado por quem usa o objeto, porém fiz um estudo um pouco detalhado sobre isto, pois tive diversos problema do esquecimento de fechamento de consultas.

Vou estar publicando o código no Github e poderá acompanhar.

solução!

Olá Hermivaldo!

Realmente confundi as bolas com a minha explicação. Você está certo e o resultado é o mesmo independente da implementação escolhida mas existe mais um detalhe importante que pode influenciar na performance do seu aplicativo.

Se olharmos o código da classe SQLiteOpenHelper vemos que uma vez que realizamos uma chamada para o getReadableDatabase() ou getWritableDatabase(), abrimos o banco de dados a partir de um arquivo e guardamos uma instância de um SQLiteDatabase no SQLiteOpenHelper. Toda vez que precisarmos de uma referência para o banco, o SQLiteOpenHelper só precisa devolver esta instância que já está cacheada.

O problema ocorre quando chamamos o método close() ou no SQLiteDatabase ou no SQLiteOpenHelper. Quando fazemos isso, aquela instância cacheada do banco recebe o valor null e da próxima vez que você for precisar de uma instância do banco, o SQLiteOpenHelper precisará abrir novamente o banco de dados. Como essa é uma operação com arquivos, ela não é uma operação barata para ser realizada a cada operação do banco (pensando naquele cenário onde queremos realizar muitas operações em sequência). Nesse caso seria mais adequado manter o banco aberto, fazer todas as operações e depois fechá-lo.

Caso tenha interesse em ver como tudo isso que eu escrevi funciona no código, siga o link abaixo que tem o código-fonte do SQLiteOpenHelper:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/database/sqlite/SQLiteOpenHelper.java#SQLiteOpenHelper.getDatabaseLocked%28boolean%29

Abraço!