61

Criando uma app Android com banco de dados SQLite

by Luiz Jr 20. novembro 2011 23:34

Android + SQLite

Hoje o post irá tratar de um assunto muito importante: persistência de dados. Todas as aplicações que lidam com um grande volume de dados devem ter algum mecanismo de persistência, mais conhecido como banco de dados, para garantir a segurança, confiabilidade e integridade dos mesmos. O Android possui um mecanismo nativo, chamado de SQLite (o mesmo utilizado pelo Corona SDK) que provê funcionalidades de SGBD para suas aplicações. Iremos ver algumas dessas funcionalidades neste post, de uma maneira bem simples, mas que servirá como base para estudos futuros.

Armazenamento persistente de dados

Para cumprir com muitas das atividades oferecidas pelos celulares modernos, como busca de contatos, eventos, e tarefas, o sistema operacional e as aplicações estar aptos a manter e rastrear grandes quantidades de dados. A maior parte destes dados está estruturado como uma planilha, na forma de linhas e colunas. Cada aplicação Android é como uma ilha por si só, e cada aplicação somente consegue ler e escrever dados criados por ela mesma, mas muitas vezes é necesário compartilhar dados além de suas fronteiras. Android suporta características de um provedor de conteúdo para que as aplicações possam compartilhar dados. Existe uma interface Java para que o Android possa se comunicar com a base de dados relacional SQLite. Esta interface suporta uma implementação de SQL rica o suficiente para qualquer coisa que você queira em uma aplicação mobile, incluindo facilidades como cursores.

Bases de Dados

Dados são melhores armazenados em um formato de base de dados relacional se ela puder incluir muitas instâncias de um mesmo tipo de dado. pegue uma lista de contatos, por exemplo. Existem muitos contatos, todos com os mesmos tipos de informação (endereço, telefone, etc). Cada "linha" de dados armazena informações sobre uma pessoa diferente, enquanto cada "coluna" armazena um atributo específico de cada pessoa: nomes em uma coluna, endereços em outra coluna, e telefone em uma terceira.

Android usa a engine de base de dados SQLite, uma auto-contida, engine transacional que não requer um processo de servidor para funcionar. Ele é usado por muitas aplicações e ambientes além de Android, e é desenvolvido por uma grande comunidade.

O processo que inicia a operação de base de dados, como um SELECT ou UPDATE, faz o trabalho necessário de leitura e escrita no disco que contém a base de dados visando completar a requisição. Com SQLite, a base de dados é um simples arquivo no disco. Todas as estruturas de dados formando uma base de dados relacional - tabelas, views, indíces, etc. - estão contidas neste arquivo.

SQLite não é um projeto do Google, embora o Google contribua com o mesmo. SQLite tem um time internacional de desenvolvedores dedicados a melhorar as capacidades do software e sua confiabilidade. Alguns desses desenvolvedores trabalham full time no projeto.

Confiança é a característica chave do SQLite. Mais de metade do código do projeto é devotado a biblioteca de testes. A biblioteca é desenvolvida para lidar com muitos tipos de falhas de sistema, como pouca memória, erros de disco, e falhas de energia. Em nenhum caso a base de dados pode ficar em um estado irreparável: isto é uma grande preocupação em um telefone onde muitos dados críticos são armazenados em bases de dados. Se a base de dados fosse suscetível a corrupção de arquivos, o telefone estaria em sérios apuros quando a bateria acabasse...

Este post irá tratar dos percalços para se criar uma aplicação muito simples que consuma dados no SQLite e não se atrá à sintaxe SQL propriamente. Um pouco de Engenharia de Software será utilizada, mantendo toda a lógica de acesso à dados em uma única classe chamada ContextoDados.java como segue (ela ainda não está completa, iremos construindo-a ao longo do post):

 

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQuery;
import android.util.Log;

public class ContextoDados extends SQLiteOpenHelper {

	/** O nome do arquivo de base de dados no sistema de arquivos */
	private static final String NOME_BD = "Agenda";
	/** A versão da base de dados que esta classe compreende. */
	private static final int VERSAO_BD = 1;
	private static final String LOG_TAG = "Agenda";
	/** Mantém rastreamento do contexto que nós podemos carregar SQL */
	private final Context contexto;
	
	public ContextoDados(Context context) {
		super(context, NOME_BD, null, VERSAO_BD);
		this.contexto = context;
		}

	@Override
	public void onCreate(SQLiteDatabase db) 
	{
		String[] sql = contexto.getString(R.string.ContextoDados_onCreate).split("\n");
		db.beginTransaction();
		
		try 
		{
			// Cria a tabela e testa os dados
			ExecutarComandosSQL(db, sql);
			db.setTransactionSuccessful();
		} 
		catch (SQLException e) 
		{
			Log.e("Erro ao criar as tabelas e testar os dados", e.toString());
		} 
		finally 
		{
			db.endTransaction();
		}
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
	{
		Log.w(LOG_TAG, "Atualizando a base de dados da versão " + oldVersion + " para " + newVersion + ", que destruirá todos os dados antigos");
		String[] sql = contexto.getString(R.string.ContextoDados_onUpgrade).split("\n");
		db.beginTransaction();
		
		try 
		{
			ExecutarComandosSQL(db, sql);
			db.setTransactionSuccessful();
		}
		catch (SQLException e) 
		{
			Log.e("Erro ao atualizar as tabelas e testar os dados", e.toString());
			throw e;
		} 
		finally 
		{
			db.endTransaction();
		}
		
		// Isto é apenas didático. Na vida real, você terá de adicionar novas colunas e não apenas recriar o mesmo banco
		onCreate(db);
	}
	
	/**
	* Executa todos os comandos SQL passados no vetor String[]
	* @param db A base de dados onde os comandos serão executados
	* @param sql Um vetor de comandos SQL a serem executados
	*/
	private void ExecutarComandosSQL(SQLiteDatabase db, String[] sql)
	{
		for( String s : sql )
			if (s.trim().length()>0)	
				db.execSQL(s);
	}
}

 

Estrutura Básica da classe ContextoDados

Em nosso exemplo, a classe ContextoDados encapsula completamente toda a lógica SQL necessária para trabalhar com a base de dados. Todas as outras classes na aplicação não possuem acesso aos dados diretamente, usando ContextoDados como uma interface de abstração dos mesmos. Esta é uma boa prática de programação e deve ser aplicada em todas suas aplicações Android que utilizem base de dados.

Antes de aprofundarmo-nos nos detalhes da aplicação em si, é importante entender o funcionamento da classe ContextoDados. Esta classe herda de SQLiteOpenHelper, e sobrescreve (override) os métodos onCreate e onUpgrade. O método onCreate é automaticamente chamado quando a aplicação roda pela primeira vez; sua tarefa é criar a base de dados. Como novas versões daaplicação podem ser lançadas, a base de dados pode ser atualizada também, uma tarefa que dispara o método onUpgrade. Quando você entrega uma nova versão da base de dados, você também deve incrementar a versão, como irei explicar rapidamente a seguir.

E por fim, o método ExecutarComandosSQL é um método para facilitar a execução de comandos SQL múltiplos, que apenas chama os comandos nativos do Android para execução de comandos SQL.

A classe ContextoDados utiliza duas strings estáticas (que ficam no arquivo strings.xml): R.string.ContextoDados_onCreate e R.string.ContextoDados_onUpgrade com os scripts de criação e atualização do banco de dados. Estas strings estão abaixo e não passam de um SQL comum, quevocê já deve estar acostumado:

<string name="ContextoDados_onCreate">
        CREATE TABLE Contatos (ID INTEGER PRIMARY KEY AUTOINCREMENT, Nome TEXT,    Telefone TEXT, Endereco TEXT);
</string>
<string name="ContextoDados_onUpgrade">"
        DROP TABLE IF EXISTS Contatos
</string>

Lendo dados da base

Existem muitas maneiras de ler dados de uma base SQL, mas todos eles fazem uma sequência básica de operações:

  1. Cria um comando SQL que descreve os dados que você deseja retornar
  2. Executa o comando na base de dados
  3. Mapeia os dados SQL resultantes em uma estrutura de dados que a linguagem que você está utilizando possa entender.

Este processo pode ser muito complexo no caso de um software de mapeamento objeto relacional, ou relativamente simples quando escrevendo as consultas diretamente em sua aplicação. A diferença é a fragilidade. Ferramentas complexas de ORM protegem seu código das complexidades inerentes às bases de dados e o mapeamento de objetos, movendo esta complexidade para eles mesmos. O resultado é um código mais robusto face às alterações na base, mas ao custo de mais complexidade na configuração e manutenção do ORM.

A iniciativa de escrever consultas diretamente na sua aplicação trabalha bem somente para projetos bem pequenos que não irão mudar muito com o passar do tempo. Aplicações com código de base de dados são muito frágeis devido às alterações da mesma, pois todo o código que referenciava um elemento alterado deve ser examinado e potencialmente reescrito.

Uma técnica "meio-termo" é capturar toda a lógica de base de dados em um grupo de objetos cujo único propósito é traduzir as requisições da aplicação em requisições de banco de dados e entregar os resultados de volta para a aplicação. Esta opção é a utilizada em nossa aplicação de teste utilizando a classe ContextoDados.java.

Android nos dá a habilidade de personalizar cursores, e eu usarei essa característica para reduzir dependências de código escondendo toda a informação sobre uma operação de dados específica dentro d eum cursor personalizado. Cada cursor personalizado é uma classe dentro da classe ContextoDados, no nosso caso, somente o ContatosCursor.

Desta forma, criei um método RetornarContatos, cuja função é retornar um ContatosCursor preenchido com contatos da base de dados. O usuário pode escolher (através de um simples parâmetro) para ordenar os contatos por Nome crescente ou decrescente (este código vai dentro da classe ContextoDados criada anteriormente):

 

/** Retorna um ContatosCursor ordenado
	* @param critério de ordenação
	*/
	public ContatosCursor RetornarContatos(ContatosCursor.OrdenarPor ordenarPor) 
	{
		String sql = ContatosCursor.CONSULTA + (ordenarPor == ContatosCursor.OrdenarPor.NomeCrescente ? "ASC" : "DESC");
		SQLiteDatabase bd = getReadableDatabase();
		ContatosCursor cc = (ContatosCursor) bd.rawQueryWithFactory(new ContatosCursor.Factory(), sql, null, null);
		cc.moveToFirst();
		return cc;
	}
	
	public static class ContatosCursor extends SQLiteCursor
	{
		public static enum OrdenarPor{
			NomeCrescente,
			NomeDecrescente
		}
		
		private static final String CONSULTA = "SELECT Contatos.ID, Nome, Endereco FROM Contatos ORDER BY Nome ";
		
		private ContatosCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query) 
		{
			super(db, driver, editTable, query);
		}
		
		private static class Factory implements SQLiteDatabase.CursorFactory
		{
			@Override
			public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query) 
			{
				return new ContatosCursor(db, driver, editTable, query);
			}
		}
		
		public long getID()
		{
			return getLong(getColumnIndexOrThrow("Contatos.ID"));
		}
		
		public String getNome()
		{
			return getString(getColumnIndexOrThrow("Nome"));
		}
		
		public String getEndereco() 
		{
			return getString(getColumnIndexOrThrow("Endereco"));
		}
	}

Tela de listagem

Como o foco deste post não é a criação de um layout ideal para exibição de dados, criei um bem simples que utiliza um TextView para mostrar os dados do banco concatenando strings. O código XML abaixo mostra como deve ser codificado o layout main.xml e a imagem mostra como ele deve se parecer:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/contatos"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/listaContatos"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Nenhum contato cadastrado." />

    <Button
        android:id="@+id/btnNovo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Novo Cadastro" />
   
</LinearLayout>

E o código Java a seguir mostra o início da codificação da Activity principal, que mantém o nome padrão de MainActivity.java (este código vai dentro do corpo da classe MainActivity):

 

Button btnSalvar, btnCancelar, btnNovo;
EditText txtNome, txtEndereco, txtTelefone;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CarregarInterfaceListagem();
    }
    
    public void CarregarInterfaceListagem()
    {
    	setContentView(R.layout.main);
        
        //configurando o botão de criar novo cadastro
        btnNovo = (Button)findViewById(R.id.btnNovo);
        btnNovo.setOnClickListener(new OnClickListener(){
			public void onClick(View v) {
				CarregarInterfaceCadastro();
			}});
        
        CarregarLista(this);
    }

Neste trecho de código podemos ver as chamadas aos métodos CarregarLista (mostrado abaixo) e mais a seguir implementaremos o CarregarInterfaceCadastro:

 

public void CarregarLista(Context c)
    {
    	ContextoDados db = new ContextoDados(c);
        ContatosCursor cursor = db.RetornarContatos(ContatosCursor.OrdenarPor.NomeCrescente);
        
        for( int i=0; i < cursor.getCount(); i++)
        {
        	cursor.moveToPosition(i);
        	ImprimirLinha(cursor.getNome(), cursor.getTelefone());
        }
    }
    
    public void ImprimirLinha(String nome, String telefone)
    {
    	TextView tv = (TextView)findViewById(R.id.listaContatos);
    	
    	if(tv.getText().toString().equalsIgnoreCase("Nenhum contato cadastrado."))
    		tv.setText("");
    	
    	tv.setText(tv.getText() + "\r\n" + nome + " - " + telefone);
    }

Este código nada mais faz do que concatenar strings em um TextView para simular uma listagem de dados vindos do banco. Com o código que vimos até agora, já é possível listar os dados que já estão no banco, mas provavelmente você irá querer escrever também, que veremos na próxima parte!

Escrevendo no Banco de Dados

Voltando ao ContextoDados, o trecho de código a seguir insere um novo registro no banco de Contatos e serve como exemplo para futuras inserções em outras tabelas (este código vai dentro da classe ContextoDados):

 

public long InserirContato(String nome, String telefone, String endereco)
	{
		SQLiteDatabase db = getReadableDatabase();
		
		try
		{
			ContentValues initialValues = new ContentValues();
			initialValues.put("Nome", nome);
			initialValues.put("Telefone", telefone);
			initialValues.put("Endereco", endereco);
			return db.insert("Contatos", null, initialValues);
		}
		finally
		{
			db.close();
		}
	}

Cadastro.xml - Como deve se parecer

E agora devemos criar o layout para a tela de cadastro, que chamei de cadastro.xml. A seção a seguir mostra o código XML para o layout, e a imagem à direita, como ele deve se parecer se tudo estiver correto:

<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/lblNome"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_x="8dp"
        android:layout_y="9dp"
        android:text="@string/lblNome"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <TextView
        android:id="@+id/lblTelefone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_x="7dp"
        android:layout_y="52dp"
        android:text="@string/lblTelefone"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <TextView
        android:id="@+id/lblEndereco"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_x="8dp"
        android:layout_y="95dp"
        android:text="@string/lblEndereco"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <EditText
        android:id="@+id/txtNome"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:layout_x="78dp"
        android:layout_y="8dp"
        android:inputType="textPersonName" >

        <requestFocus />
    </EditText>

    <EditText
        android:id="@+id/txtTelefone"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:layout_x="78dp"
        android:layout_y="50dp"
        android:inputType="phone" />

    <EditText
        android:id="@+id/txtEndereco"
        android:layout_width="180dp"
        android:layout_height="40dp"
        android:layout_x="78dp"
        android:layout_y="93dp"
        android:inputType="textPostalAddress" />

    <Button
        android:id="@+id/btnSalvar"
        android:layout_width="82dp"
        android:layout_height="wrap_content"
        android:layout_x="173dp"
        android:layout_y="142dp"
        android:text="@string/btnSalvar" />

    <Button
        android:id="@+id/btnCancelar"
        android:layout_width="92dp"
        android:layout_height="wrap_content"
        android:layout_x="78dp"
        android:layout_y="141dp"
        android:text="Cancelar" />

</AbsoluteLayout>

Note que neste layout temos alguns EditTexts e dois botões. O botão de cancelar apenas retorna à tela inicial, com a listagem tosca de contatos. Já o botão de salvar, deve invocar o método de inserir novo registro, da classe ContextoDados. O código restante da MainActivity está abaixo, para que você possa copi-colar:

 

public void CarregarInterfaceCadastro()
    {
    	setContentView(R.layout.cadastro);
    	
    	//configurando o botão de cancelar cadastro
        btnCancelar = (Button)findViewById(R.id.btnCancelar);
        btnCancelar.setOnClickListener(new OnClickListener(){
			public void onClick(View v) {
				CarregarInterfaceListagem();
			}});
        
        //configurando o formulário de cadastro
        txtNome = (EditText)findViewById(R.id.txtNome);
        txtEndereco = (EditText)findViewById(R.id.txtEndereco);
        txtTelefone = (EditText)findViewById(R.id.txtTelefone);
        
        //configurando o botão de salvar
        btnSalvar = (Button)findViewById(R.id.btnSalvar);
        btnSalvar.setOnClickListener(new OnClickListener(){
			public void onClick(View v) {
				SalvarCadastro();
			}});
    }
    
    public void SalvarCadastro()
    {
    	ContextoDados db = new ContextoDados(this);
		db.InserirContato(txtNome.getText().toString(), txtTelefone.getText().toString(), txtEndereco.getText().toString());
		setContentView(R.layout.main);
		CarregarLista(this);
    }

 

O código é auto-descritivo, mas caso tenha alguma dúvida, não hesite em perguntar pelos comentários.

Conclusões

Este post mostrou o básico de seleção e inserção de dados, com uma exibição bem tosca, longe de ser a ideal para uma base de dados. Você realizar o download dos fontes completos do projeto no link abaixo. Posts futuros devem cobrir outros aspectos da persistência de dados, como deleção e atualização, bem como listagem profissional dos dados usando ListAdapters. Mas isto fica pra próxima!

Para se aprofundar nestes assuntos, recomendamos o livro Google Android, da Editora Novatec.

Agenda.zip (68,85 kb)

Tags: , , , ,

Android | BD | Java | Mobile | SQLite

Comentários

Daniel Crocciari
Daniel Crocciari Brasil
23/12/2011 10:05:06 #

Luiz excelente post, porém tenho uma dúvida, em caso de exibir este cursor em uma lista, como faria isso, já que a consulta deveria ser feita com um RawQuery?

anderson
anderson Brasil
29/12/2011 09:26:07 #

Bom dia,

Estou com uma duvida, na verdade mais com um problema,quero fazer uma busca em um banco de dados SQLite pelo android com o eclipse onde esse banco possui 2 colunas uma de perguntas e outra de respostas, e mostra elas na tela do  emulador.
estou conseguindo puxar os dados do banco mas estou com dificuldade em mostra na tela essas informações, se puder me ajudar fiquei muito grato.

Desde já agradeço a ajuda,


Anderson
email:relatorio_tec@hotmail.com

Heber Mattos
Heber Mattos Brasil
13/1/2012 20:23:42 #

pessoal, segue uma solucao bem simples para jogar dados do banco em uma listview ;)

arquivo de layout do listview:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    <TextView
        android:id="@+id/name_entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="28dip" />
       <TextView
        android:id="@+id/number_entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="28dip" />
</LinearLayout>


trecho de codigo com uma possivel solucao:

.
.
.
//simpleCursorAdapter REQUER uma coluna _id, entao a solucao for dar um cast...
Cursor cursor = db.rawQuery("SELECT id _id, login, senha FROM usuario", null);
//startManagingCursor vincula o clico de vida co cursor à activity
startManagingCursor(cursor);  

//busca o nosso layout            
ListView minhaLista = (ListView)findViewById(R.id.layoutLista);
            
//quais colunas vamos mostrar...            
String[] colunas = new String[]{"login","senha"};
//... e aonde vamos coloca-las
int[] to = new int[] { R.id.name_entry, R.id.number_entry };

//instancia o SimpleCursorAdapter com os dados...             
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(contexto, R.layout.cursoradapter, cursor, colunas, to);

//..e mostra!            
minhaLista .setAdapter(mAdapter);
.
.
.

espero ter ajudado ^^

luizfduartejr
luizfduartejr Brasil
13/1/2012 20:45:58 #

Grande Heber, valeu por ajudar o pessoal! Comentem se funcionou!

Fernando Amado
Fernando Amado Brasil
25/1/2012 16:50:03 #

Quando cliquei em Gravar apresentou a mensagem:
android the application has stopped unexpectedly
após isso sempre que tento rodar a aplicação já da esse erro e fecha.

Alguem sabe o que pode estar errado?

Carlos Daniel
Carlos Daniel Brasil
13/4/2012 11:09:19 #

Ótimo post colega, bom quando os amigos compartilham o conhecimentos, sempre auxiliando no progresso de outros.

Daniel Pozzatti
Daniel Pozzatti Portugal
22/4/2012 20:42:54 #

Primeiramente parabéns pelo blog e pelo tutorial, sou novo na programação com android e sqlite. Mas o tutorial deu para ter uma luz bem legal do funcionamento. Agora tenho uma duvida, essa aplicação cria um banco de dados no próprio dispositivo, agora se eu quiser ter a base de dados em um servidor e aceder a partir do dispositivo com android, como devo fazer?
Por exemplo a agenda de contactos, a base de dados estaria num servidor e através do smartphone com android como faria para aceder a lista de contactos e introduzir um novo contacto?


Agradeco desde ja


Daniel Pozzatti
danielroitman@hotmail.com

luizfduartejr
luizfduartejr Brasil
29/4/2012 20:21:22 #

Boa noite Daniel, não sou nenhum mestre no assunto, mas pelo que sei o Android não oferece suporte (ao menos nativo) para conexões remotas com bancos de dados. Uma alternativa seria criar um website que expusesse esses dados via webservice ou GET mesmo e poderia consumi-lo a partir de sua aplicação.

Antonio
Antonio Brasil
7/6/2012 09:56:17 #

Excelente post. Deu pra aprender bastante coisa, parabens!

Só uma pergunta bem noob: Ao excluir o app do android, o banco tbm é excluido junto?

Valeu!!!

luizfduartejr
luizfduartejr Brasil
13/6/2012 14:22:47 #

Sim Antônio, o banco é excluído junto com a aplicação.

Fred
Fred Brasil
15/7/2012 10:46:08 #

Muito bom o post, tenho uma dúvida: Como faria uma tela de busca utilizando o rawQuery? Estou precisando disso.

luizfduartejr
luizfduartejr Brasil
24/7/2012 10:23:46 #

Bom dia Fred,

você terá de usar uma ListActivity para fazer isso. Tem um outro post neste blog sobre o curso de Android que ministrei em algumas faculdades e nos fontes do curos tem um exemplo de como fazer isso. Se eu tiver tempo uma hora dessas eu faço um post dedicado a esse assunto.

valdir
valdir Brasil
5/9/2012 13:44:27 #

cara, meu código ficou dando erro no  ContatosCursor cursor = db.RetornarContatos(ContatosCursor.OrdenarPor.NomeCrescente);

mas o erro so aponta para o ContatosCursor. gostaria de saber o que está havendo. e qual a solução possível

luizfduartejr
luizfduartejr Brasil
5/9/2012 20:25:35 #

Boa noite Valdir,

no post luiztools.com/post/Curso-de-Android-Basico.aspx tem um zip para download que contempla vários aspectos do desenvolvimento mobile com banco de dados. Dá uma olhada nos arquivos para ver se consegue encontrar uma solução para o seu problema.

AlbertoCatarino
AlbertoCatarino Brasil
10/9/2012 18:59:56 #

Fiz o exemplo e quando faço o deploy no emulador, as duas activities que usei aparecem separadas. Nao aparece o nome do propjeto e sim das activities. O que estou fazendo errado?

luizfduartejr
luizfduartejr Brasil
10/9/2012 19:30:24 #

Boa noite Alberto, dá uma revisada no teu manifesto. Lá é onde as activities ficam descritas e inclusive é onde definimos a Activity inicial (Launcher), nome do projeto e por aí vai.

Rafael Costa
Rafael Costa Brasil
16/10/2012 21:53:20 #

Parabens pelos post, caros amigo estou com grandes dificuldades, estou criando um guia virtual utilizano eclipse e SQLITE, 1 fiz todo procedimento para funcionar o gps (incluindo a chave), mas a unica coisa que aparece um ponto na tela no emulador e mais nada, não sei o que fazer. 2 eu criei duas tabelas de de banco de dados utilizando listview, mas da um mensagem de erro acusando que não tem nada de bando de dados, tambem não sei o que fazer.

luizfduartejr
luizfduartejr Brasil
17/10/2012 10:40:24 #

Bom dia Rafael, dá uma olhada no código-fonte que eu disponibilizo neste post luiztools.com/post/Curso-de-Android-Basico.aspx ele vai te ajudar com suas dúvidas de SQLite.

Victor
Victor Brasil
3/11/2012 11:36:56 #

Cara muito obrigado por este post, você me deu uma luz, tava caçando na internet e os tutorias não me ajudaram muito, mais o seu foi diferente, muito obrigado mesmo funfou de boa aqui, vlw

luizfduartejr
luizfduartejr Brasil
3/11/2012 13:35:07 #

Boa tarde Victor, que bom que gostou.
Dá uma olhada nos outros posts de Android pois tem um deles que disponibilizo os fontes de uma aplicação completa que também acessa SQLite, pode te ajudar com mais informações.

Fred
Fred Brasil
3/11/2012 14:36:30 #

Está utilizando o DAO nesse exemplo?

luizfduartejr
luizfduartejr Brasil
3/11/2012 15:39:17 #

No exemplo que citei eu não uso o conceito puro de DAO, embora tenha algumas coisas em comum, mas mostro um esboço do que futuramente pode vir a se tornar um ORM para Android. Quem sabe isso não vira o TCC da minha pós-graduação? É um problema que muita gente tem.

Fred
Fred Brasil
3/11/2012 16:05:28 #

É possível utilizar um banco de dados externo? Como fazer?

luizfduartejr
luizfduartejr Brasil
3/11/2012 16:35:11 #

Não é possível conectar diretamente a um banco externo, assim como é comumente feito em Java. Você terá de criar uma API, um webservice por exemplo, que sua aplicação irá acessar para consumir os dados. O webservice por sua vez é que se conectará ao banco, podendo ser desenvolvido em qualquer linguagem.

Cássyo Kist
Cássyo Kist Brasil
12/11/2012 11:43:34 #

Olá, estou tendo problemas com essa parte do código...
String[] sql = contexto.getString(R.string.ContextoDados_onCreate).split("\n");
o eclipse simplesmente não reconhece esta parte do comando  "R.string.ContextoDados_onCreate", como eu resolvo isso?
att.

luizfduartejr
luizfduartejr Brasil
12/11/2012 13:18:23 #

Bom dia Cássyo,

Não deve estar funcionando pois ele está fazendo uma referência ao arquivo Strings.xml que você não deve ter populado.

Troque a "R.string.ContextoDados_onCreate" pela string SQL de criação das suas tabelas. Ex: "CREATE TABLE tbCliente(id integer primary key, nome text not null);"

Cássyo Kist
Cássyo Kist Brasil
12/11/2012 13:41:01 #

Hmmm, obrigado pela ajuda Luiz, mas como eu faço o Upgrade então?
pois eu necessito do nome da tabela certo?

luizfduartejr
luizfduartejr Brasil
12/11/2012 13:52:43 #

Tu pode guardar o nome da tabela em uma constante se precisar. Lembre-se que o OnUpgrade somente é chamado durante uma atualização da versão do software, ou seja, não é necessário a menos que esteja lançando o sistema na Google Play. Se estiver apenas estudando ou desenvolvendo para terceiros, deixe ele de lado por enquanto.

Cássyo Kist
Cássyo Kist Brasil
12/11/2012 14:00:46 #

Então Luiz, estou desenvolvendo sim para a Google Play, mas é estranho pois eu executo a aplicação e não consigo ver o banco criado nem nada no File Explorer, eu olhei vários tutoriais ( o seu foi o melhor), porém não estou conseguindo ver a mágica acontecendo ^^

String sql = "CREATE TABLE Divisoes(id INT AUTO_INCREMENT, descricao VARCHAR(25)," + "numpessoas INT, valoraluguel DOUBLE, PRIMARY KEY(id));";

por enquanto está assim.

Cássyo Kist
Cássyo Kist Brasil
12/11/2012 14:18:49 #

Luiz, eu executo minha aplicação, mas o banco não é criado, eu nao consigo visualizá-lo no File Explorer pelo menos, você sabe me dizer o por que?

luizfduartejr
luizfduartejr Brasil
12/11/2012 14:41:30 #

Boa tarde Cássyo, dá uma revisada na sua sintaxe, até onde sei não existem estes tipos que está usando nas colunas no SQLite. Se não me engano temos apenas o integer, o text e o real. Provavelmente é por isso que não está criando o banco, sugiro dar uma lida na documentação do mesmo no site oficial http://www.sqlite.org

Adriano
Adriano Brasil
15/11/2012 21:48:05 #

deu um erro que não consigo solucionar
NomeCrescente cannot be resolved or is not a field

nessa parte do código oque seria isso??????
public void CarregarLista(Context c)
{
  Contextodados db = new Contextodados(c);
    ContatosCursor cursor = db.RetornarContatos(ContatosCursor.OrdenarPor.NomeCrescente);
    
    for( int i=0; i < cursor.getCount(); i++)
    {
      cursor.moveToPosition(i);
      ImprimirLinha(cursor.getNome(), cursor.getTelefone());
    }
}

luizfduartejr
luizfduartejr Brasil
15/11/2012 22:43:08 #

Boa noite Adriano,

NomeCrescente é um enumerador de ordenações, ele não é vital para o funcionamento do projeto, pode editar esta parte do código sem problemas. Sugiro conferir meus posts mais recentes dos cursos de Android que possuem exemplos de código-fonte onde acesso bases SQLite de uma maneira melhor.

heber mattos
heber mattos Brasil
21/11/2012 00:10:28 #

fica a dica pessoal....

ORM GreenDAO para Android SQLite!

ORM? pt.wikipedia.org/wiki/Mapeamento_objeto-relacional

GrennDAO? http://greendao-orm.com/

Taskz com pequena integração: www.4shared.com/.../Task_ORM_greendao.html

qual a moral? super resumo... ;)

cria-se um projeto java (não android, java msm) separado, com freemaker.jar e greendao-generator.jar referenciados no buildpath (taskzGenerator no exemplo) com uma classe (TaskzGenerator.java) que vai criar, no seu projeto da aplicacao quando executado manualmente, todos os teus objetos (DAOmaster, tarefa, tarefaDao, etc )necessarios para manipulacao e persistencia. referencia no buildpath no projeto principal greendao.jar e pronto!

como se insere uma nova tarefa?

tarefaDao.insert(new Tarefa((long) 1,"teste texto"))

td prontinho e arrumadinho ^^


André Luís
André Luís Brasil
23/11/2012 10:53:14 #

Bom dia Luiz!

Muito legal o seu tutorial!! Parabéns!!
Mas estou com uma dificuldade. Preciso que o banco de dados da minha aplicação, já venha com dados, e não que ele seja criado quando for iniciado o aplicativo.
Você sabe como fazer isso?

luizfduartejr
luizfduartejr Brasil
23/11/2012 11:06:03 #

Bom dia André, você vai ter de criar o banco e na sequência cadastrar todos os registros iniciais do seu banco.
Outra alternativa é ao executar a app pela primeira vez você baixar o seu banco pronto de algum lugar, mas isso exigirá que o usuário tenha conexão com  Internet, algumas permissões específicas no manifesto e por aí vai.

João
João Brasil
11/12/2012 06:06:04 #

Ótimo post, ja estou com a aplicação funcionando e com o código bem organizado, porém me surgiu uma dúvida, no post temos funcções para criar as tabelas, inserir, fazer select, mas e pra excluir um registro ? E pra dar um update ?

Claro, se tratando de SQL é muito simples, mas como faria utilizando o Java no meio campo ?


Se puder dar um help agradeço!

Abraço

luizfduartejr
luizfduartejr Brasil
11/12/2012 07:25:53 #

Bom dia João, db.execSQL pra executar qualquer comando SQL e db.rawQuery para qualquer consulta SQL. Simples assim.

João
João Brasil
11/12/2012 17:17:18 #

Que beleza, eu demorei um pouquinho pra entender toda a implementação do post, mas agora está tudo claro...

Me diga outra coisa, aproveitando que o post é sobre DB, fiz uma aplicação para iOS onde o usuarios tiram fotos ou usam as que já existem no aparelho, salvo elas no Banco de dados do próprio app já que em IOS não temos tantos problemas com a falta de espaço...

Estou fazendo agora a versão para Android, já tenho o código funcionando para tirar foto ou usar imagens existentes, mas queria saber como salvar essas imagens na DB, estava lendo também, que o ideal seria salva-las no cartão SD e inserir na DB somente o caminho, porém se por algum motivo o usuário apagar perder ou seila as imagens que foram salvas terei problemas na minha aplicação, ja que o caminho salvo anteriormente foi quebrado.


Qual sua opnião sobre isso ? Qual seria uma boa prática ?


Mais uma vez obrigado!

luizfduartejr
luizfduartejr Brasil
11/12/2012 18:12:32 #

Boa noite João, não é devido à falta de espaço que não devemos salvar imagens em bancos de dados, é devido à performance. Executar queries em tabelas com grandes blocos de dados por linha é extremamente lento e consome muita CPU e memória. O ideal é sempre que possível (exceto em bancos NoSQL) salvar as imagens "puras" em um diretório e somente os caminhos no banco.

Com relação ao problema do usuário perder o SD, as próprias aplicações nativas do Android trabalham dessa maneira, caso você tire o SD, as imagens exibirão uma miniatura de imagem quebrada, indicando que você fez m****. Mais do que isso, se tu ir apenas no diretório e apagá-las, ele também apresentará o mesmo comportamento.

Caso desempenho não seja um problema na sua aplicação (sei lá, talvez você vá rodá-la sempre em um dispositivo específico, com boa CPU e RAM), de repente pode ser uma boa manter tudo no banco. Do contrário, evite.

Max Soares
Max Soares Brasil
5/1/2013 15:11:17 #

Luiz, excelente post! Será muito útil.
Tenho um problema. Eu criei um projeto Android pelo Eclipse e gerei o APK dele. Apenas com a tela de login. Quando eu instalo isso no Tablet com Android 4.0, simplesmente não aparece ícone nenhum no dispositivo para acessar a tela de login. Apenas aparece que o dispositivo foi instalado com sucesso. No menu configurações > aplicações aparece que ele foi instalado, porem não aparece o icone para eu acessá-lo. Já o seu projeto da agenda consegui instalar e acessar normalmente.
O que há de errado com o APK gerado pelo Eclipse?

abraço.

luizfduartejr
luizfduartejr Brasil
5/1/2013 15:55:55 #

Boa tarde Max. Você está procurando pelo ícone correto? É meio estranho perguntar isso, mas quando não sabemos qual ícone estamos procurando, é muito fácil não encontrarmos no menu, hehehehe.

Nunca tive problemas de gerar APK pelo Eclipse e não aparecer ícone no menu. Cria um Hello World, instala o APK e vê se acontece o mesmo.

Roberto
Roberto Brasil
17/2/2013 19:27:59 #

Luiz, Parabéns pelo post. Muito útil. aprendi muito e ainda aprendendo mais.
Experimentei o seguinte problema:
Quando incluia um cadastro, o botão Novo Cadastro deixa de funcionar.
Como a implementação do botão esta dentro de CarregarInterfaceListagem(), ao chamar o Ativity novamente ele não é implementado. É isso mesmo?
Corrigi trocando a última chamada em SalvarCadastro() de  CarregarLista(this) para CarregarInterfaceListagem(), o que implementa o botão novamente.
meu entendimento está certo ou qual seria a melhor solução pra isso?

Grato

luizfduartejr
luizfduartejr Brasil
17/2/2013 19:34:16 #

Boa noite Roberto,

que bom que lhe foi útil, mesmo sendo um post velho e desatualizado, hehehehe.

Sim, o seu entendimento está correto.

Pedro
Pedro Brasil
26/3/2013 23:24:04 #

Poderia dar uma olhada no link?
Não estou conseguindo baixar.
Parabéns pela iniciativa, belo site!
Att. Pedro

luizfduartejr
luizfduartejr Brasil
26/3/2013 23:42:17 #

Link corrigido. Valeu pelo toque!

JGFerreira
JGFerreira Brasil
5/5/2013 21:51:20 #

Eu ando lendo muito e surgem muitas dúvidas.

Minha dúvida é como eu faço para criar um banco de de Dados com informações só para serem acessadas(consultadas)

Por exemplo tenho 3 spinners e um botão. Vou colocar um exemplo

na 1º Spinner eu teria opções de escola, hospitais, praças (Lugares Públicos)...
na 2º Spinner eu teria as opções de zonas da cidade,( zona 1, zona2, zona3..)
na 3º spinner os principais os bairros da cidade( bairro A, bairro B...)

se a spinner 1 eu escolher Escola
e a spinner 3 eu escolher o Bairro A,
e a pessoa clicar no botão pesquisar
como eu faço para na próxima tela apresentar todas as escolas do Bairro A ??


Não é pra inserir nada, queria saber como faz um banco de dados apenas para consultar dados inseridos!
De modo que quando alguém selecionar o Bairro A, na tela seguinte faria uma query sobre esses dados (ex. select * from escola where bairro = 'A')
Como eu faço isso??

luizfduartejr
luizfduartejr Brasil
5/5/2013 22:13:07 #

Boa noite Jessica,

para criar as tabelas basta executar os comandos SQL apropriados, como "CREATE TABLE ..." sobre uma conexão SQLite. Dá uma olhada na parte que eu falo do evento onCreate, é lá que você cria as tabelas.

Depois você terá de inserir seus dados, certo? Pois mesmo que o usuário não insira manualmente, seu sistema vai ter de ter os cadastros previamente. Para cada inserção, ainda no evento onCreate, você terá de executar um comando SQL INSERT.

Só por último é que o banco estará pronto para seus usuários poderem realizar as consultas. Essa parte pelo que entendi você já entende bem, pois inclusive me citou o comando SQL correto como exemplo.

Boa sorte!

Novato
Novato Portugal
7/5/2013 18:58:17 #

Olá, ótimo post

Mas luiz como eu crio uma tabela com estados e paises
de modo que eu a selecionar um determinado país e um determinado estado, na outra tela me apareça as informações desse estado?

Por favor, faça um exemplo usando alguns estados brasileiros

Como fui dito em cima, eu tbm estarei usando spinner e não edit text

luizfduartejr
luizfduartejr Brasil
7/5/2013 19:58:30 #

Boa noite Jessica, estou impossibilitado de desenvolver aplicativos para o blog no momento devido aos meus outros compromissos. Sugiro que dê uma lida na documentação do SQLite que ensina como criar tabelas.

O lance dos spinners também é bem simples, no evento de change de um é só mandar carregar o outro selecionando os registros do banco.

Uma hora que sobrar um tempinho eu escrevo um post sobre isso.

Um abraço.

Alexandre Marins
Alexandre Marins Brasil
20/7/2013 09:01:19 #

Muito bom os post seu, parabéns.

Alexandre Marins
Alexandre Marins Brasil
20/7/2013 09:02:21 #

Bom dia, gostei muito do seu post, estou lendo o seu blog todo.

luizfduartejr
luizfduartejr Brasil
20/7/2013 12:14:13 #

Boa tarde Alexandre, que bom que está gostando. Pena que não tenho tido tempo de atualizá-lo ultimamente. De qualquer forma, obrigado pelas visitas e boa leitura!

Bruno
Bruno Brasil
10/8/2013 19:58:44 #

Post muito bom....luiz gostaria de saber como buscar um dado por row..
por exemplo

Medidor    |   Litros  

0.1        |   100

Eu ja criei essa tabela...mas gostaria de cria um campo que se colocasse 0.1 retornasse 100 litros.

luizfduartejr
luizfduartejr Brasil
11/8/2013 02:10:09 #

Boa noite Bruno, basta fazer um select normal sobre essa tabela, mas desta vez aplicando um filtro na consulta. Por exemplo, digamos que ainda sobre minha tabela de contatos, eu queira retornar o endereço do contato cujo nome é Luiz, basta trocar a String com a consulta SQL para : "SELECT Endereco FROM Contatos WHERE Nome='Luiz'"

Ali onde está 'Luiz' eu posso estar colocando qualquer String, inclusive uma capturada a partir de um campo de texto.

Espero que tenha me entendido, um abraço!

Rafaela Cavalcante de Araujo
Rafaela Cavalcante de Araujo Brasil
6/9/2013 02:32:14 #

Oi Luiz, parabéns pelo tutorial!
Estou com um problema, quando eu executo a aplicação dá um erro e nem inicia, no logCat diz 'no such column: NomeASC', fiz tudo igual a você!
Ajuda por favor!

Max
Max Brasil
6/9/2013 07:34:10 #

Olá Rafaela.
Dê uma olhada no seu arquivo do banco com os campos utilizados na aplicação. Verifica se você está realmente criando este campo 'NomeASC' na tabela. Caso mesmo assim não encontre o problema, depure o sistema para localizar o erro.

Meu contato caso possa ajudar.
Skype: max.analista

Espero que consiga. Abraço.

luizfduartejr
luizfduartejr Brasil
6/9/2013 11:38:40 #

Boa tarde Rafaela,

me parece que você juntou as palavras Nome e ASC por engano (sendo que ASC é usada para ordenação). Tente separá-las para ver se funciona.

Um abraço.

Rafaela Cavalcante de Araujo
Rafaela Cavalcante de Araujo Brasil
6/9/2013 15:11:07 #

Oi Luiz obrigada por responder, na verdade é que eu modifiquei um pouco o código. Estava tentando criar duas activitys uma para carregar o layout de listar os contatos e a outra de cadastrar um novo contato, mas da sua maneira tá funcionando certinho!Tem algum problema fazer isso? Ainda não consegui resolver!
Abraço!

luizfduartejr
luizfduartejr Brasil
6/9/2013 15:55:12 #

Não é pra dar problema, pois o correto é sim separar cada "tela" em uma activity separada. Aqui pelo blog tem dois posts onde postei código fonte de cursos que ministrei. Nestes fontes tem exemplos de aplicação com tela de listagem + tela de cadastro. Dá uma procurada que acho que vai te ajudar.

Rafaela Cavalcante de Araujo
Rafaela Cavalcante de Araujo Brasil
6/9/2013 17:01:50 #

Obrigada Luiz já resolvi! Tentei novamente e funcionou com as duas activitys!
Abraço!

Comentar


(Vai mostrar seu Gravatar)

  Country flag

biuquote
  • Comentário
  • Pré-visualização
Loading



Powered by BlogEngine.NET 1.6.1.0
Design por Laptop Geek, adaptado por onesoft e personalizado por mim.