sábado, 28 de junho de 2014

Android: acesso SqLite multi-thread

 Estava acompanhando um colega com problemas com acesso concorrente ao banco de dados SqLite, ele conseguiu resolver os problemas com as informações de um artigo que encontrara no blog de um desenvolvedor Android de nome Dmytro Danylyk.
 Como, quem me lê, sabem, sou particularmente interessado em processamento concorrente, então fiz algumas pequenas adaptações na solução do Dmytro para fazer alguns testes.
 Para fazer acesso concorrente no Android é necessário que se faça com uma única conexão ao db, para isso deve-se usar apenas um objeto SQLiteOpenHelper, fiz a classe DatabaseController, um singleton (olha o padrão aqui novamente!), para controlar o acesso ao banco de dados.
 Como é para ser compartilhado por diversas threads todos os métodos são sincronizados. O controle do número de acessos é controlado pelo atributo mOpenCounter, para somente fechar o banco quando for a última solicitação de close, para evitar fechar o banco enquanto uma outra thread ainda esteja em processamento.

 Para os meus testes, fiz um pequeno banco de mensagens, os objetos salvos no banco estão no RowTab.java e fiz um TesteDbAdapter.java para usar o DatabaseController. Para obter uma referência ao controlador usa-se: "DatabaseController.getInstance();". E para inicialização do SQLiteOpenHelper coloquei o método "setDatabaseHelper(contexto);". Para ter uma referência ao SQLiteDatabase usa-se o método open().
 Notem que a abertura do db somente vai ocorrer no primeiro open, e quando o db for criado, esta operação pode ser demorada, por isso, sempre é recomendado executar o primeiro open (caso seja o caso) numa thread diferente da main thread do Android.
 A activity é bem simples e direta, no onCreate chamo o método ativaThread() e nela inicio quatro threads para usar o banco concorrentemente.

Seguem os códigos:

DatabaseController.java


RowTab.java



TesteDbAdapter.java



MainActivity.java


 Para checar, após o fim das threads, aguarde os Toasts terminarem, aperte o back e no onDestroy loga o número de linhas da tabela.

 Testem aí, funciona!

 Abraços.

PS: segue o link do Dmytro https://github.com/dmytrodanylyk/dmytrodanylyk/blob/gh-pages/articles/Concurrent%20Database%20Access.md