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