En
Android Labs nos proponen un tutorial bastante completo,
Notepad Tutorial, un gestor de notas.
El tutorial se sigue en forma de ejercicios, 3 más uno extra. De cada ejercicio tenemos un código base y su solución por si tenemos algún problema.
Nos
descargamos el código base y las soluciones, y nos
preparamos el entorno para empezar con el
ejercicio 1.
Ejercicio 1
En este
ejercicio 1 construiremos una lista de notas a la que podremos añadir nuevas notas, pero no editaralas.
Paso 1
Abrimos el proyecto
Notepadv1 en Eclipse. Este proyecto es el punto de inicio para el ejercicio 1.
- File > New > Android Project
- Seleccionamos Create project from existing source
- Seleccionamos el directorio Notepadv1 que nos hemos descargado antes
- La mayoría de propiedades del proyecto se rellenan automáticamente. Seleccionamos el Target, en Android Labs nos recomiendan seleccionar la versión del sdk menor para que sea compatible con la mayor cantidad de dispositivos.
- Pulsamos en Finish
Yo no he tenido problemas, pero si en vuestro caso tenéis algún problema con el
AndroidManifest.xml, con el botón derecho en el proyecto seleccionamos
Android Tools >
Fix Project Properties, para que dejen de salirnos.
Paso 2
Echamos un vistazo a la clase
NotesDbAdapter, que nos servira para acceder a la base de datos
SQLite que utilizaremos para guardar las notas.
Al principio de la clase tenemos unas cuantas constantes declaradas:
private static final String DATABASE_CREATE =
"create table notes (_id integer primary key autoincrement, "
+ "title text not null, body text not null);";
Esta es la consulta que crea la tabla de notas, que contiene 3 campos,
_id,
title y
body, de los que también tenemos sus constantes:
public static final String KEY_TITLE = "title";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";
También tenemos una constante que identifica la clase a la hora de escribir en log:
private static final String TAG = "NotesDbAdapter";
El constructor de la clase
NotesDbAdapter toma como parámetro un objeto de clase
Context. Esto es para poder acceder a propiedades y métodos del sistema (
Android).
En el método
open() creamos un instancia de la clase
DatabaseHelper, que es un clase local que implementa
SQLiteOpenHelper. Con el método
getWritableDatabase() obtenemos la base de datos.
Con el método
close() simplemente cerramos la conexión con la base de datos.
Al método
createNote() le pasamos un
String title y otro
body para crear una nueva nota en la base de datos. Si se crea bien, devolveremos un
long que sera el
_id del nuevo registro creado en la tabla.
Con
deleteNote() podemos eliminar un registro de la tabla pasándole el
_id.
Para obtener todos los registros de la tabla usaremos
fetchAllNotes(). Este método nos retorna un
Cursor (según
Android Labs el sistema es más eficiente que con
collections). Dentro del método llamamos a
SQLiteDatabase.query() con los parámetros: nombre de la tabla (
String), columnas que queremos recuperar (
array de Strings, y otros campos que dejamos a
null para obtener todos los datos sin agrupar, ni ordernar. (Ver detalles en
SQLiteDatabase).
fetchNote() funciona de una forma similar que
fetchAllNotes(), pero le pasamos un
_id para obtener un registro determinado.
Para actualizar un nota utilizaremos
updateNote(), al que le pasaremos
_id de la nota que modificar, y los valores actualizados.
Paso 3
Abrimos el fichero
res/layout/notepad_list.xml y vemos un
LinearLayout vacío. Si alguien no identifica o conoce algo que se pase por
HelloLinearLayout.
Paso 4
.
Copiamos el siguiente cógido en
res/layout/notepad_list.xml para crear la vista del listado de notas
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ListView android:id="@android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_notes"/>
</LinearLayout>
Es una vista bastante sencilla, en la que tenemos un
ListView y un
TextView. Suponiendo que ya conocemos un poco de vistas (si no, mirar
HelloLinearLayout), lo importante son los
id de estos dos elementos. Vemos que empiezan los dos por
@android:id/, esto quiere decir que nos lo proporciona la plataforma
Android. Pues usaremos 'automáticamente'
@android:id/list cuando tengamos notas y
@android:id/empty cuando no haya notas.
Paso 5
Para cada fila o item de la lista también deberemos generar una vista. Creamos un fichero nuevo en
res/layout y lo llamamos
notes_row.xml. El contenido será:
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/text1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Podemos observar que en el
id tenemos los carácteres
@+. El
+ indica que los elementos que usan esta vista se generan dinámicamente y el
id se creará automáticamente si todavía no existe.
Paso 6
Abrimos la clase
Notepadv1 y le cambiamos la clase padre
Activity por
ListActivity. Esta clase añade funcionalidad extra para trabajar con listas.
Si miramos el código vemos que tenemos un atributo
mNoteNumber que todavía no usamos, pero que haremos servir para numerar las notas.
También vemos que sobreescribimos tres métodos:
- onCreate: llamado cuando la Activity empieza. Una especie de main
- onCreateOptionsMenu: llamado cuando el usuario pulsa en botón de menu
- onOptionsItemSelected: cuando pulsamos en el botón de menú, normalmente lanzamos una lista de acciones, como por ejemplo "Crear Nota". Pues este método es llamado cuando el usuario pulsa en una opción de estas.
Paso 7
El método
onCreate() debe quedarnos así:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notepad_list);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
fillData();
}
Después de las dos líneas típicas de un
onCreate() (
super.onCreate() y
setContenView()), creamos la instancia del
NotesDbAdapter, al que le pasamos el
context. Abrimos la conexión y rellenamos los datos con
fillData(), método que todavía no hemos implementado.
Paso 8
En el método
onCreateOptionsMenu() copiamos:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean result = super.onCreateOptionsMenu(menu);
menu.add(0, INSERT_ID, 0, R.string.menu_insert);
return result;
}
Para que el código compile debemos añadir en el
res/value/strings.xml:
Add Item
Y añadimos en la clase
Notepadv1 la siguiente constante:
public static final int INSERT_ID = Menu.FIRST;
De esta manera hemos añadido un botón ("Add Item") que aparecerá cuando pulsemos en el botón de menú del dispositivo.
Paso 9
En
onOptionsItemSelected() copiamos:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case INSERT_ID:
createNote();
return true;
}
return super.onOptionsItemSelected(item);
}
Este método se ejecutará cuando pulsemos en un opción del menú. Recibe como parámetros un
MenuItem, el cuál comprobamos si es la primera opción ("Add Note") para crear una nota nueva con
createNote(). Finalmente llamaremos al método de la superclase con super.
onOptionsItemSelected().
Paso 10
Para este ejercicio 1 implementaremos un versión poco útil del método
createNote(). Simplemente crearemos una nota nueva vacía asignándole un titulo incluyendo un contador. La nota no se podrá modificar de momento.
private void createNote() {
String noteName = "Note " + mNoteNumber++;
mDbHelper.createNote(noteName, "");
fillData();
}
Paso 11
Por último tenemos que implementar el método
fillData(). El código es:
private void fillData() {
Cursor c = mDbHelper.fetchAllNotes();
startManagingCursor(c);
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
Para rellenar los datos usamos un
SimpleCursorAdapter. Cuando creamos un objeto
SimpleCursorAdapter le pasamos los siguientes parámetros:
- this --> Contexto
- int layout --> identificador del layout que contiene la lista de elementos a rellenar
- Cursor --> Cursor de la base de datos
- String[] --> Array de las columnas a rellenar
- int[] --> Array de las vistas/layouts que mostrarán los datos
Para poder trabajar con el cursor, la clase
Activity nos da el método
startManagingCursor(Cursor c).
Paso 12
Ejecutamos la aplicación