Mostrando postagens com marcador AsyncQueryHandler. Mostrar todas as postagens
Mostrando postagens com marcador AsyncQueryHandler. Mostrar todas as postagens

domingo, 31 de janeiro de 2016

Acessando o SQLite de forma assíncrona

Olá povo,

Não importa o quanto eu estude, sempre tem algo novo sobre Android que eu não sabia. Conversando com os meus amigos Diego Nascimento e André [Mion], descobri a classe AsyncQueryHandler que nos permite realizar as transações de banco de dados em uma Thread separada.
Acho que a maioria de vocês deve saber que quando o usuário está interagindo com o aplicativo, ele está utilizando o que chamamos de Main Thread ou UI Thread. Para que não tenhamos problemas de desempenho na renderização da UI, ela deve executar a 60 fps (frames por segundo). Se fizermos um cálculo rápido, podemos constatar que nenhuma operação que é feita na UI Thread deve demorar que 16 milissegundos. Caso contrário, perderemos frames a aplicação e o usuário começará a notar a aplicação "travando" ou demorando a responder.
Aqui no blog já falei sobre várias técnicas para não utilizar a Main Thread, tais como: AsyncTask, AsyncTaskLoader e LoaderManager. Essa última, em particular resolver parte do problema do título desse post, pois com o CursorLoader + LoaderManager podemos fazer a consulta em Content Provider em background. Perfeito! Mas... E as operações de inclusão, exclusão e atualização?
Para esses casos temos a classe AsyncQueryHandler. Essa classe facilita a realização dessas operações em background. Embora, o SQLite seja muito rápido, caso você esteja fazendo uma transação que utilize várias tabelas, ou mesmo que trabalhe com muitos registros, esse processamento poderá demorar bem mais que 16ms.
A utilização dessa classe é bem simples.
public void inserir() {
    ContentValues values = new ContentValues();
    values.put("titulo", "Lembrete");
    values.put("descricao", "Escrever post");

    Uri uri = Uri.parse("content://seu.content.provider/mensagens");

    // Começa o processo assíncrono
    new MeuAsync(getActivity()).startInsert(0, null, uri, values);
}

class MeuAsync extends  AsyncQueryHandler {
    // Usando WeakReference para evitar leak da Activity
    private WeakReference<Context> mContext;

    public MeuAsync(Context ctx) {
        super(ctx.getContentResolver());
        mContext = new WeakReference<>(ctx);
    }

    @Override
    protected void onInsertComplete(int token, Object cookie, Uri uri) {
        super.onInsertComplete(token, cookie, uri);
        if (mContext.get() != null) {
            Toast.makeText(mContext.get(),
                    "Registro inserido com sucesso!",
                    Toast.LENGTH_SHORT).show();
        }
    }
}
Perceba que estamos utilizando o método startInsert() passando como parâmetro: um identificador para essa transação; um objeto qualquer que podemos utilizar posteriormente no método de callback (aqui passamos null); a URI para o seu Content Provider; e os valores que serão inseridos.
De forma semelhando, poderíamos utilizar os métodos: startUpdate(), startDelete() e startQuery().

Na classe MeuAsync, ficam os métodos que serão chamados após a realização da operação em background. No nosso exemplo utilizamos apenas o o onInsertComplete. Mas nos casos de atualização, exclusão e busca de registros, utilizaríamos os métodos onUpdateComplete(), onDeleteComplete e onQueryComplete().

4br4ç05,
nglauber