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
6 comentários:
Interessante essa classe. Mas lá vai algumas duvidas, 1- Se a minha aplicação não tiver um Content Provide como usar essa classe? 2- Quando eu for criar um banco de dados para minha aplicação tenho que criar um Content Provide é aconselhável ?
Oi Alessandro,
Content Provider é um dos quatro principais componentes do Android (junto com Activity, Service e Broadcast Receiver).
Seu uso é altamente recomendado e facilita bastante a integração com outros componentes do sistema. Sem contar que temos uma forma padrão de abstrair o acesso a dados do aplicativo.
4br4ç05,
nglauber
Comecei a pouco tempo no android, comprei o seu livro pra me ajudar e tá ajudando bastante mas o que eu queria saber era se seguir o livro é o suficiente? Eu vou tentando reproduzir os códigos mas na grande maioria das vezes tenho que olhar o seu código pra conseguir seguir adiante, você teria alguma dica? Qual seria a melhor forma de realmente aprender a programar para android?
email:hugaleno@gmail.com
Agradeço a atenção desde já,
Hugaleno Bezerra, mero mortal! :)
Oi Hugaleno,
Primeiramente obrigado por adquirir o livro, tomara que goste e aprenda muito com ele.
Em relação a sua pergunta, posso dizer sem sombra de dúvidas que APENAS o livro NÃO é suficiente. Digo isso, porque até hoje acho coisas que não sabia sobre Android a cada dia que trabalho com a plataforma. Esse post é um exemplo disso (e outros como o RecyclerView).
É importante participar de eventos, ver vídeos, e achar outras fontes de consulta para analisar os pontos fortes e fracos de cada uma.
Então visite sempre:
http://developer.android.com (site oficial dos desenvolvedores Android com documentação, treinamentos, etc.)
http://android-developers.blogspot.com.br/ (blog oficial sobre Android que trás as novidades sobre Android)
https://www.udacity.com/courses/android (site com cursos gratuitos sobre Android patrocinado pelo Google)
Ah! E para aprender "realmente", tem que ter alguns aplicativos desenvolvidos :)
4br4ç05,
nglauber
Como roda em uma Thread separada, não pode ocorrer erro do banco já ter uma conexão aberta? Neste caso retornar que o banco está bloqueado?
Oi CNT Cardoso,
O fato de ser em uma thread separada não quer dizer que você terá várias threads acessando o banco. E mesmo assim o SQLite suporta operações de insert, delete e update em múltiplas threads desde que seja com a mesma conexão (instância de SQLiteOpenHelper).
A boa prática é sempre fechar o banco ao terminar uma operação e tudo ficará bem :)
4br4ç05,
nglauber
Postar um comentário