En uno de los artículos anteriores uno de los lectores del blog preguntó por algún ORM que facilitara el acceso a base de datos en Android. Debido a que desconocía en ese momento ninguno, me propuse buscar alguno que pudiera cumplir con los objetivos.
He de reconocer que tampoco busqué mucho, y al final dí con ORMLite que cuenta con una versión para Android. De este modo, y basándome en uno de los múltiples ejemplos de los que posee el proyecto creé un simple proyecto que simula una agenda de contactos que almacena por cada contacto el nombre, email y número de teléfono.
Tanto la parte visual como el control de excepciones no está muy trabajado, ya que consideraba que no era el objetivo del artículo y quería ir directo al grano.
Para empezar, lo primero que debemos hacer es descargas las librerías y enlazarlas en nuestro proyecto. Básicamente, debería bastar con ormlite-core-4.28.jar y ormlite-android-4.28.jar (como podemos observar, la versión actual es la 4.28)
A continuación mostramos dos de los archivos responsables del funcionamiento del ejemplo, aunque no van a ser explicados ya que son bastante autoexplicativos (AndroidManifest.xml y main.xml):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="es.jmanzano.ormlite.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".OrmliteActivity"
android:label="ORML" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/queryResults"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Welcome to the ORMLite example" />
</ScrollView>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#FFFFFF" >
<TableRow>
<TextView
android:text="Name:"
android:width="100dp" />
<EditText
android:id="@+id/etName"
android:width="190dp" />
</TableRow>
<TableRow>
<TextView android:text="Email:" />
<EditText android:id="@+id/etEmail" />
</TableRow>
<TableRow>
<TextView android:text="Telephone number:" />
<EditText android:id="@+id/etTelephoneNumber" />
</TableRow>
<TableRow android:id="@+id/TableRow03" >
<Button
android:id="@+id/bShowContacts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Show contacts" />
<Button
android:id="@+id/bAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Add Contact" />
</TableRow>
</TableLayout>
</RelativeLayout>
A continuación podemos ver la clase principal de nuestro modelo de datos: Contact. En ella por medio de las anotación @DatabaseField determinaremos los miembros que van a ser almacenados en base de datos
package es.jmanzano.ormlite.example;
import com.j256.ormlite.field.DatabaseField;
/**
* A simple model object to store a Contact
*/
public class Contact {
@DatabaseField(generatedId = true)
int id;
@DatabaseField
String name;
@DatabaseField
Integer telephoneNumber;
@DatabaseField
String email;
Contact() {
// needed by ormlite
}
public Contact(String name, Integer telephoneNumber, String email) {
this.name = name;
this.telephoneNumber = telephoneNumber;
this.email = email;
}
@Override
public String toString() {
return name + ": " + telephoneNumber + ", " + email;
}
}
Y comenzando con la configuración de la Base de datos por medio de ORMLite, debemos declarar el fichero ormlite_config.txt en la carpeta raw
#
# --table-start--
dataClass=es.jmanzano.ormlite.example.Contact
tableName=contact
# --table-fields-start--
# --field-start--
fieldName=id
generatedId=true
# --field-end--
# --field-start--
fieldName=name
# --field-end--
# --field-start--
fieldName=telephoneNumber
# --field-end--
# --field-start--
fieldName=email
# --field-end--
# --table-fields-end--
# --table-end--
#################################
Aquí declararemos la clase que persistiremos, en este caso Contact y los campos correspondientes con table-field-start y table-field-end.
Por último nos queda por definir el DatabaseHelper (conocido por todos los que hemos definido alguna vez alguna interacción con la BBDD de Android).
package es.jmanzano.ormlite.example;
import java.sql.SQLException;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.RuntimeExceptionDao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
/**
* Database helper class used to manage the creation and upgrading of your database. This class also usually provides
* the DAOs used by the other classes.
*/
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// name of the database file for your application
private static final String DATABASE_NAME = "contact.db";
// any time you make changes to your database objects, you may have to increase the database version
private static final int DATABASE_VERSION = 1;
// the DAO object we use to access the SimpleData table
private Dao<Contact, Integer> simpleDao;
private RuntimeExceptionDao<Contact, Integer> simpleRuntimeDao;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config);
}
/**
* This is called when the database is first created. Usually you should call createTable statements here to create
* the tables that will store your data.
*/
@Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Contact.class);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* This is called when your application is upgraded and it has a higher version number. This allows you to adjust
* the various data to match the new version number.
*/
@Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try {
TableUtils.dropTable(connectionSource, Contact.class, true);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* Returns the Database Access Object (DAO) for our SimpleData class. It will create it or just give the cached
* value.
*/
public Dao<Contact, Integer> getDao() throws SQLException {
if (simpleDao == null) {
simpleDao = getDao(Contact.class);
}
return simpleDao;
}
/**
* Returns the RuntimeExceptionDao (Database Access Object) version of a Dao for our SimpleData class. It will
* create it or just give the cached value. RuntimeExceptionDao only through RuntimeExceptions.
*/
public RuntimeExceptionDao<Contact, Integer> getSimpleDataDao() {
if (simpleRuntimeDao == null) {
simpleRuntimeDao = getRuntimeExceptionDao(Contact.class);
}
return simpleRuntimeDao;
}
/**
* Close the database connections and clear any cached DAOs.
*/
@Override
public void close() {
super.close();
simpleRuntimeDao = null;
}
}
Aquí podemos ver los distintos métodos típicos de los SqliteOpenHelper: onCreate() y onUpgrade(). Como podemos ver, nos ayudaremos de la clase TableUtils para create las tablas con createTable() y dropTable() para poder borrarlas. Debemos tener en cuenta que la calse debe extender a OrmLiteSqliteopenHelper, y que en el constructor de nuestra clase debemos pasarle al constructor de la superclase el id del archivo de configuración.
Por último, mostramos la definición de la activity principal: OrmliteActivity. Aquí realizaremos tanto la creación de los registros en BBDD como la visualización:
package es.jmanzano.ormlite.example;
import java.util.List;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.RuntimeExceptionDao;
/**
* Sample Android UI activity which displays a text window when it is run.
*/
public class OrmliteActivity extends OrmLiteBaseActivity<DatabaseHelper> {
private EditText etName;
private EditText etTelephoneNumber;
private EditText etEmail;
private TextView tvResults;
private RuntimeExceptionDao<Contact, Integer> dao;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvResults = (TextView) findViewById(R.id.queryResults);
etName = (EditText) findViewById(R.id.etName);
etEmail = (EditText) findViewById(R.id.etEmail);
etTelephoneNumber = (EditText) findViewById(R.id.etTelephoneNumber);
dao = getHelper().getRuntimeExceptionDao(Contact.class);
queryForAll();
}
/**
* Query for all the regs
*/
private void queryForAll() {
// query for all of the data objects in the database
List<Contact> list = dao.queryForAll();
// our string builder for building the content-view
StringBuilder sb = new StringBuilder();
sb.append("Found " + list.size() + " results\n");
for (Contact contact : list) {
sb.append(contact.toString() + "\n");
}
sb.append("-------------------------------------------------\n");
tvResults.setText(sb.toString() + tvResults.getText());
}
private void addContact() {
StringBuilder sb = new StringBuilder();
sb.append("Added contact \"" + etName.getText().toString() + "\" to the address book\n");
dao.create(
new Contact(
etName.getText().toString(),
Integer.parseInt(etTelephoneNumber.getText().toString()),
etEmail.getText().toString())
);
sb.append("-------------------------------------------------\n");
tvResults.setText(sb.toString() + tvResults.getText());
}
public void onClick(View view) {
int id = view.getId();
if (id == R.id.bShowContacts) {
queryForAll();
} else if (id == R.id.bAdd) {
addContact();
}
}
}
Básicamente debemos comentar dos métodos, el de inserción y el de visualización, así como extender de la clase OrmliteBaseActivity parametrizándola con el database helper que hayamos definido.
- En el método
queryForAll() vemos que simplemente, teniendo una referencia al dao que estemos usando (que hemos obtenido previamente con getHelper().getRuntimeExceptionDao(Contact.class), podemos realizar una llamada al método queryForAll() para obtener todos los registros.
- Por otra parte, en el método
addContact() simplemente deberemos pasar al método create() el objeto que queremos crear, en este caso un Contact
Como hemos podido observar… en tan solo unos pasos hemos podido obtener una base de datos y realizar las operaciones de inserción y visualización de una manera muy sencilla. ¿Que os parece? ¿Os parece claro el código? ¿Usais otro ORM distinto para Android?