base de datos en android

61
[Manual] [SDK v1.0] Creación de base de datos Después de ver que han cambiado cosas durante todas las versiones que han sido saliendo de la SDK de Android voy a intentar explicar como crear y usar una base de datos en Android. Es únicamente una manera porque hay más, y si alguien ve otras maneras estaría muy bien que las fuera poniendo. 1. Lo mejor es que creemos una nueva clase donde tendremos los métodos que van a crear la base de datos y van a hacer las peticiones que nos devolverán los datos que guardamos, así como para insertarlos cómodamente. Agregamos lo primero una variable global que apunte a la base de datos que vamos a crear y añadiremos la librería de SQLiteDatabase que necesitaremos. Es importante que añadamos el contexto en el constructor ya que lo necesitaremos para crear la base de datos. Código : import android.database.sqlite.SQLiteDatabase; public class BD{ SQLiteDatabase db; public BD(Context ctx){ //constructor //apertura de base de datos //creación de tablas } } 2. Añadimos la creación o apertura de la base de datos. Lo hacemos mediante el contexto, para ello, el primer argumento del método "openOrCreateDatabase" es el nombre que tendrá la base de datos, el segundo indicará si es de lectura, escritura o ambas, por defecto se pone 0 para ambas, y el tercer argumento no tengo muy claro que es, pero según las APIs se tiene que añadir la clase que será llamadapara instanciar un cursor (clase Cursor supongo) cuando se hace alguna petición. Por ahora lo dejamos en null. Código : db = ctx.openOrCreateDatabase("bdprueba", 0, null); 3. Ya tenemos la base de datos abierta y si no estuviera creada la crea y la abre. El siguiente paso será crear las tablas. Para ello lo más fácil es crear Strings con la sentencia de creación de las tablas, las podéis poner en un archivo separado o como variable global, es indiferente. Código : String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS tablita (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "dato text NOT NULL);"; Después habrá que ejcutar ese comando para la creación de la tabla, por eso, justo después de la creación o apertura de la base de datos añadiremos la ejecución de ese String.

Upload: luis-alfredo-lucero-varillas

Post on 20-Jan-2016

24 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Base de Datos en Android

[Manual] [SDK v1.0] Creación de base de datos

Después de ver que han cambiado cosas durante todas las versiones que han sido saliendo de la SDK de Android voy a intentar explicar como crear y usar una base de datos en Android. Es únicamente una manera porque hay más, y si alguien ve otras maneras estaría muy bien que las fuera poniendo.

1. Lo mejor es que creemos una nueva clase donde tendremos los métodos que van a crear la base de datos y van a hacer las peticiones que nos devolverán los datos que guardamos, así como para insertarlos cómodamente.

Agregamos lo primero una variable global que apunte a la base de datos que vamos a crear y añadiremos la librería de SQLiteDatabase que necesitaremos.

Es importante que añadamos el contexto en el constructor ya que lo necesitaremos para crear la base de datos.

Código :

import android.database.sqlite.SQLiteDatabase;

public class BD{

SQLiteDatabase db;

public BD(Context ctx){ //constructor //apertura de base de datos //creación de tablas }}

2. Añadimos la creación o apertura de la base de datos. Lo hacemos mediante el contexto, para ello, el primer argumento del método "openOrCreateDatabase" es el nombre que tendrá la base de datos, el segundo indicará si es de lectura, escritura o ambas, por defecto se pone 0 para ambas, y el tercer argumento no tengo muy claro que es, pero según las APIs se tiene que añadir la clase que será llamadapara instanciar un cursor (clase Cursor supongo) cuando se hace alguna petición. Por ahora lo dejamos en null.

Código :

db = ctx.openOrCreateDatabase("bdprueba", 0, null);

3. Ya tenemos la base de datos abierta y si no estuviera creada la crea y la abre. El siguiente paso será crear las tablas. Para ello lo más fácil es crear Strings con la sentencia de creación de las tablas, las podéis poner en un archivo separado o como variable global, es indiferente.

Código :

String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS tablita (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "dato text NOT NULL);";

Después habrá que ejcutar ese comando para la creación de la tabla, por eso, justo después de la creación o apertura de la base de datos añadiremos la ejecución de ese String.

Page 2: Base de Datos en Android

Código :

db.execSQL(CREATE_TABLE);

4. Es importante que añadamos capturas de excepciones porque si la base de datos está creada e intenta crear la tabla saltará la excepción y se saldrá, de esa manera la capturaremos y podemos verla en los Logs.

Recuerdo que para poder ver luego los logs bien hay que filtrar y habrá que añadir una referencia.

Código :

try{

}catch(Exception e){ Log.d("BASEDEDATOS", "Exception initDB: " + e.toString());}

5. Ahora vamos a añadir algún valor a la tabla, para ello crearemos un método para poderlos meter automáticamente. Se puede hacer fácilmente con la misma sentencia que se ha utilizado para la creación de las tablas, pero ahora usaremos uno de los métodos que Android nos da.

Para ello le daremos el dato que queremos introducir (sólo tenemos ese campo, si no habría que poner el resto) y creamos un ContentValues, esta clase contendrá el nombre del campo de la tabla que queremos añadir el valor y el valor que tendrá mediante "put". Una vez introducidos todos, se añaden mediante "insert", indicando el nombre de la tabla, el segundo argumento no tengo claro qué es porque la explicación que dan las APIs es que se utilice para no peritir introducir una línea completamente vacía, pero por defecto lo ponemos a null y en el tercer argumento introduciremos los ContentValues antes guardados.

La función devolverá un long ya que eso devuelve el insert, devolviendo el ID de la línea insertada o -1 en caso de error.

Código :

public long addDato(String dato){ ContentValues cV = new ContentValues(); cV.put("dato", dato); return db.insert("tablita", null, cV); }

6. Si queremos recoger datos podemos crear otro método para facilitar el proceso. Al igual que en el paso anterior, se podría hacer mediante un simple exe, pero vamos a utilizar otro método que nos da Android para hacer peticiones. Sin duda si se utiliza bien se pueden conseguir métodos sencillos y bastante automáticos para todas las peticiones que necesitemos.

Lo primero que debemos crear es un array de String con el nombre de todas las columnas que queremos conseguir. Después creamos el cursor donde se nos devolverán los datos de la petición.

La petición se hace mediante el método "query" y contiene muchos campos: - nombre de la tabla - lista de columnas (array de String creado antes) - la selección, lo que s epondría en la cláusula WHERE

Page 3: Base de Datos en Android

- argumentos de la selección - group by - having - order by - limit

Si sabes hacer sentencias SQL será muy sencillo porque es igual, pero no hay que armarlas en Strings enormes, por lo que es bastante más cómodo al menos a mi parecer.

Y como siempre que hacemos algo en SQL hay que recoger cualquier excepción que pudiera salir.

Después habrá que leer el cursor devuelto, para ello hay que ir pasando al siguiente en todo momento, con un simple bucle "while" conseguiremos pasar por todos de manera sencilla e introducir los datos donde queramos. También podemos enviar el cursor y luego ya evaluarlo donde queramos, pero en mi caso he querido devolver un "ArrayList" de Strings, por lo que va leyendo todos los datos sacados y los devuelve después en el "ArrayList".

Cuando hace el "getString" hay que indicarle qué columna quieres coger, que será el entero que va entre paréntesis.

Código :

public ArrayList<String> getDatos(String txt){ String[] columns = {"dato"}; Cursor c = null; try{ c = db.query("dato", columns, "null", null, null, null, "dato"); }catch(Exception e){ Log.d("BASEDEDATOS", "Exception getMakes: " + e.toString()); } ArrayList<String> aL = new ArrayList<String>(); while(c.moveToNext()) aL.add(c.getString(0)); return aL; }

-----------------------------------------------------------------

La clase quedaría algo así:

Código :

.....package.....

import android.database.sqlite.SQLiteDatabase;.....otros imports que se necesiten.....

public class BD{

SQLiteDatabase db; String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS tablita (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "dato text NOT NULL);";

public BD(Context ctx){ try{ //apertura de base de datos db = ctx.openOrCreateDatabase("bdprueba", 0, null); //creación de tablas db.execSQL(CREATE_TABLE);

}catch(Exception e){

Page 4: Base de Datos en Android

Log.d("BASEDEDATOS", "Exception initDB: " + e.toString()); } }

public long addDato(String dato){ ContentValues cV = new ContentValues(); cV.put("dato", dato); return db.insert("tablita", null, cV); }

public ArrayList<String> getDatos(String txt){ String[] columns = {"dato"}; Cursor c = null; try{ c = db.query("dato", columns, "null", null, null, null, "dato"); }catch(Exception e){ Log.d("BASEDEDATOS", "Exception getMakes: " + e.toString()); } ArrayList<String> aL = new ArrayList<String>(); while(c.moveToNext()) aL.add(c.getString(0)); return aL; }}

7. Para llamar a la clase lo podemos hacer desde la clase principal, la "Activity", crearemos una variable global de la clase que hemos creado, y después en el método que primero se ejecuta "onCreate" crearemos una instancia de la base de datos, que después ya podremos utilizar libremente.

Código :

BD db; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); db = new BD(this); }

No descarto que haya algo mal sobretodo si se copia directamente el último código dado, lo he explicado para que se entienda todo más o menos y puedas continuar creando cosas, si tienes alguna duda o crees que hay algo mal o quieres ampliarlo no dudes en decirlo.

Espero que sirva de ayuda.

Saludos.

[Manual] Crear menús.

Hola a todos:

Visto que alguno sigue teniendo dudas de como implementar nuestro propio menú en las aplicaciones, voy a poneros un trozo de código que es bastante explicativo.

Page 5: Base de Datos en Android

A la primera parte se le llama una vez dentro de nuestra aplicación y es la encargada de montar el menú. Aquí deberemos ir añadiendo las diferentes opciones.

@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu);

menu.add(0, 0, "Zoom"); menu.add(0, 1, "Settings"); menu.add(0, 2, "Other"); return true; }

Lo segundo es crear el método que entienda que hay que hacer cuando se pulsa en cada una de las acciones de nuestro menú.

@Override public boolean onOptionsItemSelected(Menu.Item item){ switch (item.getId()) { case 0: showAlert("Menu Item Clicked", "Zoom", "ok", null, false, null); return true; case 1: showAlert("Menu Item Clicked", "Settings", "ok", null, false, null); return true; case 2: showAlert("Menu Item Clicked", "Other", "ok", null, false, null); return true; } return false; }

El ejemplo es muy sencillito, y lo único que hace es enseñarnos ventanas de alerta al presionar sobre las opciones del menú.

El menú tiene muchos parámetros configurables, algunos intentaré ir poniéndolos aquí por si no se entienden bien, os animo a que investiguéis y vayáis probando cosas.

[Manual] Notificaciones en la barra de estado

Hola a todos:

Aquí os dejo un sencillo tutorial para aprender a lanzar notificaciones en la barra de estado.

A petición popular he creado un sencillo programa que coloca la bandera de tú país en la barra de notificaciones.

<div align="center"><br><img src="http://s4.subirimagenes.com/imagen/3420539device.png"></div>

Código android:

Page 6: Base de Datos en Android

package indra.android.taller;

import android.app.Activity;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;import android.os.Bundle;

public class Notificaciones extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //Recuperamos el administrador de notificaciones NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

//Nos creamos una nueva notificación, con el icono de la bandera que nosotros queramos, sin texto y lista para lanzarse Notification notification = new Notification(R.drawable.spain, "",System.currentTimeMillis()); //Definimos la interfaz de la notificación Context context = getApplicationContext(); CharSequence contentTitle = ""; CharSequence contentText = ""; //Especificamos que acción realizar si pulsamos sobre la notificación Intent notificationIntent = new Intent(this, Notificaciones.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); //Lanzamos la notificación mNotificationManager.notify(0, notification); //Cerramos la aplicación finish(); }}

[Manual] ListView (principiantes)

Hola a todos. Ahí os dejos este manual para iniciarse con los ListView. Está escrito para 1.5, quizas para versiones anteriores no funcione correctamente.

El ListView de Android es un objeto simple para la representación de una lista en texto plano. Este es la primera parte de una serie de tutoriales, si dios quiere, en los que veremos como crear un ListView con poco trabajo. En este articulo veremos dos técnicas para crear una ListView cuyas filas contienen iconos y texto. Si quiere que las filas tengan un aspecto distinto, una forma de lograrlo es proporcionar su propio Layout que usara para cada fila, esto dirá a Android que use su layout en lugar de uno propio. Esto le proporciona un control sobre lo que sucede en la fila y la forma en que se representa.

Por ejemplo, supongamos que usted quiere un ListView cuyas entradas se componen de un icono, seguido de un texto. Tu debes construir un layout para las filas como el siguiente xml:

Page 7: Base de Datos en Android

Fichero (main.xml)

Código XML:

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

<LinearLayout

android:id="@+id/LinearLayout01"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical"

xmlns:android="http://schemas.android.com/apk/res/android"

>

<ListView

android:id="@+id/android:list"

android:layout_width="fill_parent"

android:layout_height="250px"

>

</ListView>

<TextView

android:id="@+id/seleccion"

android:layout_width="200px"

android:layout_height="30px"

>

</TextView>

</LinearLayout>

Fichero (fila.xml)

Código XML:

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

<LinearLayout

android:id="@+id/listado_filas"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical"

xmlns:android="http://schemas.android.com/apk/res/android"

>

Page 8: Base de Datos en Android

<ImageView

android:id="@+id/icono"

android:layout_width="50px"

android:layout_height="50px"

android:src="@drawable/si"

>

</ImageView>

<TextView

android:id="@+id/texto"

android:layout_width="200px"

android:layout_height="30px"

>

</TextView>

</LinearLayout>

Este diseño (fila.xml)usa un LinearLayout para la creación de una fila, con el icono a la izquierda y el texto a la derecha.

Por defecto, sin embargo, Android no tiene ni idea de que tu quieras usar este diseño con el ListView, por lo tanto necesitamos asociar nuestro layout al Adapter a través del ID:

Fichero: Demo.java

Código android:

import android.app.Activity;

import android.app.ListActivity;

import android.os.Bundle;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ArrayAdapter;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.TextView;

public class Demo extends ListActivity {

TextView selection;

String[] items={"lorem", "ipsum", "dolor", "sit", "amet",

"consectetuer", "adipiscing", "elit", "morbi", "vel",

"ligula", "vitae", "arcu", "aliquet", "mollis",

"etiam", "vel", "erat", "placerat", "ante",

Page 9: Base de Datos en Android

"porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

setListAdapter(new IconicAdapter(this)); selection=(TextView)findViewById(R.id.selection);

}

}

Este ejemplo, muestra una lista aleatoria de palabras, y establece la palabra selecciona sobre el TextView. La clave de este ejemplo es usar un ArrayAdapter, pudiendo usar así una apariencia personalizada (R.Layout.fila) y establecer la lista de palabras sobre el TextView llamado en este caso R.id.texto dentro de su apariencia personalizada.

El resultado es un ListView con iconos en el margen izquierdo. Si bien es cierto que todos los iconos son los mismo.

Esta técnica, que proporciona un diseño alternativo para el uso de filas, gestiona casos simples de forma muy efectiva.

Sin embargo, esto no es valido si los diseños de las filas se complican, con son:

* No todas las filas usan el mismo diseño (Ej: Unas filas tienen una linea de texto, otras dos). * Es necesario configurar los iconos dependiendo de la fila. (Ej., diferentes iconos para diferentes casos).

En estos casos, la mejor opción es crear tus propias subclases del adaptador que deseemos, sobrescribiendo el método getView(), y construyéndolo tu mismo. El método getView() es responsable de retornar un View, representando la posición en fila proporcionada por el adaptador.

Por ejemplo, vamos a modificar el código anterior para utilizar getView (), para que pueda tener iconos diferentes para diferentes filas,en este caso, un icono de palabras cortas y otro para las palabras largas:

Fichero: DemoDinamica. Código android:

import android.app.Activity;

import android.app.ListActivity;

import android.os.Bundle;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ArrayAdapter;

import android.widget.ImageView;

Page 10: Base de Datos en Android

import android.widget.ListView;

import android.widget.TextView;

public class DemoDinamica extends ListActivity {

TextView selection;

String[] items={"lorem", "ipsum", "dolor", "sit", "amet",

"consectetuer", "adipiscing", "elit", "morbi", "vel",

"ligula", "vitae", "arcu", "aliquet", "mollis",

"etiam", "vel", "erat", "placerat", "ante",

"porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

setListAdapter(new IconicAdapter(this));

selection=(TextView)findViewById(R.id.seleccion);

}

public void onListItemClick(ListView parent, View v, int position, long id) {

selection.setText(items[position]);

}

class IconicAdapter extends ArrayAdapter {

Activity context;

IconicAdapter(Activity context) {

super(context, R.layout.fila, items);

this.context=context;

}

public View getView(int position, View convertView, ViewGroup parent) {

View row = View.inflate(this.getContext(), R.layout.fila, null);

TextView label=(TextView)row.findViewById(R.id.texto);

label.setText(items[position]);

if (items[position].length()>4) {

ImageView icon=(ImageView)row.findViewById(R.id.icono);

icon.setImageResource(R.drawable.no);

}

Page 11: Base de Datos en Android

return(row);

}

}

}

En nuestra implementación de getView(), primero usaremos el método View.inflate.

Este método permite representar una serie de datos sobre una apariencia XML especifica (nuestro Layout). Sin que tengamos que realizar el tedioso trabajo de; tomar un elemento, crear las instancias de las clase especifica View, recuperar los atributos, convertir y llamar a los setters, recorrer todos los elementos hijos, etc, hasta ver representados los datos.

Así que usaremos inflate con nuestro layout para representar la fila.

Entonces, modificaremos nuestro View dependiendo de nuestras necesidades:

* Cargaremos el texto de nuestro label, usando la palabra proporcionada por la posición del array. * Vemos si la palabra es mas larga de cuatro caracteres y, si es así, recuperamos nuestro ImageView y modificamos el icono por el adecuado.

Ahora, tenemos un ListView con diferentes iconos en base los datos de la lista. Tan solo es un ejemplo, pero nos sirve para poder ver como se usa está técnica y poder ponerla en marcha para cualquier tipo de adaptación de las filas dependiendo de un criterio.

Bueno, pues aquí os traigo la 2ª, 3ª y 4ª parte de los manuales de ListView, al igual que el primero, está actualizado para su funcionamiento en 1.5. Espero que os ayude a entender un poco mas el funcionamiento de los ListView. Entendiendo estos objetos podemos llegar a representar cualquier listado de objetos que queramos. Un saludo. Nota. Si hay cualquier error o necesitáis que se aclare algo, no dudéis en decírmelo, todos estos modelos los tengo implementados y funcionando.

LIST VIEW (Segunda parte)

En nuestro ultimo manual, vimos como crear un ListView en android que contenía mas que una simple lista de string. En particular, vimos la forma de modificar los objetos para adaptarlos a nuestras necesidades, en concreto; una subclase de Adapter, sobrescribiendo el método getView(), y retornando un View para cada una de las filas, basado en nuestro propio layout XML. Los teléfonos actuales no son la cosas mas rápida que hay. En android, crear widget(Views) es un proceso relativamente pesado, por no mencionar la gestión que ha de hacer el recolector de basura para deshacerse de ellos una vez finalizado. Por lo que, no es conveniente crear mas widget de los que ya tenemos. Ahora, vamos a imaginarnos que tenemos un ListView que, visualmente en pantalla, puede mostrar 7 registros, pero la propia lista contiene 50 registros, tal vez procedentes de una base de datos o algunos contenido parseados de internet. Crear un widget para 7 registros es mucho menos costoso en recursos que hacerlo para 50 registros. Sin embargo, nuestro getView(), nuestra implementación crea widgets cada vez que se pide. Si tu añades salidas Log podrás ver que ocurre, tu veras que si mueves el scroll a través de toda la lista, está será llamada 50 veces.

Android tiene una forma de mejorar la gestión de su getView(); esto es a través del parámetro contentView pasado como argumento a getView().

Page 12: Base de Datos en Android

Algunas veces, convertView será nulo. En estos casos, tu tienes que crear una fila (view) desde cero (a través de Inflate), tal y como se hizo en el primer manual. Sin embargo, si el convertView no es nulo, entonces lo que visualizamos es en realidad un View previamente creado. Esto ocurrirá inicialmente cuando el usuario desplace el scroll del ListView, cuando aparecen nuevas filas. Android intentará reciclar las views de las filas que han salido fuera del área visual, de esta forma ahorra tener que reconstruirlas. Asumiendo que cada una de las filas tiene la misma estructura básica, tu puedes usar findViewByid() para llegar a los widgets individuales que conforman sus filas y modificar su contenido, entonces devolver contentView desde getView(), en lugar de crear una nueva fila: Por ejemplo, aquí tenemos el getView() implementado en el primer manual, ahora optimizado con contentView:

Código android:

public View getView(int position, View convertView, ViewGroup parent) { View row=convertView; if (row==null) { row = View.inflate(this.getContext(), R.layout.fila, null); } TextView label=(TextView)row.findViewById(R.id.texto); label.setText(items[position]); if (items[position].length()>4) { ImageView icon=(ImageView)row.findViewById(R.id.icono); icon.setImageResource(R.drawable.no); } return(row);}

Comprobamos si el contentView es nulo, si es así, cargamos nuestra fila, pero sino lo es la reusamos. En ambos casos debemos rellenar el contenido del texto y la imagen, pero podemos evitarnos el paso de inflate que es el paso mas costoso. En modelo de “reciclado”, se hace complicado en diseños de varias filas y este caso pueden variar significativamente. Por ejemplo, si es necesario crear una View que requiere dos líneas de texto, no podemos utilizar un ejemplo como el actual, con una línea de texto. Por supuesto, hay formas de hacer esto, como crear una segunda línea de texto visible o invisible, dependiendo de si es necesario. En un teléfono, cada milisegundo de tiempo de CPU es precioso, simplemente por la vida de la batería. Dicho esto, sobre todo si eres un novato a Android, recomiendo centrarse en conseguir primero que la aplicación sea totalmente funcional, después mejorar el rendimiento revisando el código una vez el programa funcione correctamente. Fuente: http://www.androidguys.com/2008/07/17/fancy-listviews-part-two/

LIST VIEW (Tercera parte)

En nuestro último manual, vimos como podíamos ahorrar tiempo de procesamiento, y por lo tanto, vida de la batería, usando el reciclado de filas de nuestra lista, simplemente validando y reusando el parámetro convertView en nuestro método getView(). El objetivo, una vez mas es reducir el tiempo de trabajo que se necesita para realizar una lista, tanto para los usuarios, haciendo mas ágil la respuesta y reduciendo el consumo de batería. Otra operación costosa es el uso de las llamadas a findViewById(). Esto ha de buscar dentro de la lista de objetos de la app los indicadores de cada uno hasta encontrar el requerido. Desde findViewById() puede encontrar objetos en cualquier lugar del árbol comenzando desde el raíz. Esto conlleva un buen número de instrucciones, sobre todo si tenemos tener que volver a encontrar objetos que había buscado antes. En algunas herramientas de desarrollo este problema se evita creando las filas internamente en código (en este caso Java). Y ciertamente esto se puede hacer en Android pero el código es algo mas complejo. Ahí es donde entra ViewWrapper. Con esta clase realizaremos esté proceso mas simple y con la posibilidad de usar XML para nuestras filas Todos los objetos View contienen los métodos getTag() y setTags(). Estos métodos permiten asociar arbitrariamente un objeto con la aplicación. Si añadimos al Handler (manejador) de

Page 13: Base de Datos en Android

nuestra fila (View) , cada vez que la usamos, nos evitaremos tener que hacer la llamada al findViewById() de nuevo. Con el consiguiente ahorro de memoria y por lo tanto de batería, al reducir el numero de ciclos de reloj de la CPU. Veamos como quedaría la clase con este cambio:

Código android:

public class ViewWrapper { View base; TextView label = null; ImageView icon = null;

ViewWrapper(View base) { this.base = base; }

TextView getLabel() { if ( label == null) { label = (TextView) base.findViewById(R.id.texto); } return (label); }

ImageView getIcon() { if (icon == null) { icon = (ImageView) base.findViewById(R.id.icono); } return (icon); }}

La principal diferencia entre ViewWrapper y ViewHolder (al final del manual) es que el ViewWrapper que crear un wrapper (envoltorio) que nunca necesita un hijo especifico hace que no necesites llamar continuamente al findViewById() reduciendo así los ciclos de CPU usados para este proceso. Por otro lado, ViewHolder tiene los Views (ImageView y TextView ) como variables publicas y el ViewWrapper con métodos getter, así que habrá situaciones en las que el ViewHolder será mas eficiente que la clase ViewWrapper.

Usando la clase ViewWrapper el método getView() quedaría así: Código android:

public View getView(int position, View convertView, ViewGroup parent) { View row = convertView; ViewWrapper wrapper = null;

//*1 if (row == null) { //*2 row = View.inflate(this.getContext(), R.layout.fila, null); wrapper = new ViewWrapper(row); row.setTag(wrapper); } else { //*3 wrapper = (ViewWrapper) row.getTag(); } //*4 wrapper.getLabel().setText(items[position]);

if (items[position].length() > 4) { //*4 wrapper.getIcon().setImageResource(R.drawable.no); } return (row);}

Page 14: Base de Datos en Android

Comprobaremos si convertView es nulo (*1) con el fin de crear las filas(*2) , según sea necesarios. Sacar o crear el ViewWrapper correspondiente a cada fila (*3) . Con lo que recoger los views hijos de nuestra fila, son tan solo cuestión de llamar a los métodos asociados al Wrapper (*4).

ViewHandler.class public class ViewHolder { ImageView image; TextView text; }

Fuente: http://www.androidguys.com/2008/07/22/fancy-listviews-part-three/

LIST VIEW (Cuarta parte)

En la tercera parte del manual, vimos como podíamos hacer nuestra ListView mucho mas eficiente a la hora de renderizarse. Hoy echaremos un vistazo a como crear elementos interactivos por fila en nuestro ListView. En concreto, veremos una implementación en crudo de una lista de control: un ListView que contiene Checkbox. El ListView contendrá CheckBox, pero muchos de los conceptos que estábamos usando son validos si usamos filas del ListView que contengan botones, check o EditView. Una lista de CheckBox esta principalmente diseñada para permitir al usuario de una forma sencilla la multiselección, en particular en los casos en que varias selecciones son la norma. La lista contiene un check por linea y puede marcar los que le interesan. Para esta demo usaremos las mismas clase que en anteriores partes de los manuales. A diferencia de los anteriores en este ejemplo se mostrará una lista de check que contendrán cada una de las palabras de la lista aleatoria. Si seleccionamos una de ellas está se pondrá en mayúscula. No es el ejemplo mas sofisticado del planeta, pero nos servirá para centrar la lógica del tratamiento, pudiendo a partir de ahí expandirla para nuestro uso particular. ¿Que necesitamos hacer? Tenemos que almacenar y verificar el check seleccionado en algún lugar, ya que nuestros CheckBoxs serán reciclados cuando el usuario se mueva por el scroll. Tenemos que ser capaces de establecer el estado del Checkbox basado en la palabra real que contiene el CheckBox, y guardar el estado a medida que se mueve por el scroll no olvidemos que al mover el scroll el objeto se recicla. Lo que hace esta interesante es que, por defecto, el Checkbox no tiene absolutamente ninguna idea del objeto en el que está el ArrayAdapter. Después de todo el CheckBox es un widget, usado en una fila de un ListView. Tenemos que enseñar a las filas del modelo que están mostrando actualmente, así cuando se revisa su casilla de verificación, que sepan el estado del modelo a modificar. Entonces, con todo esto en mente, echemos un vistazo a algo de código. Esta es la clase Activity, con los cambios:

Código android:

public class ListViewDemo4 extends ListActivity { TextView selection; String[] items = { "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue", "purus" };

@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

ArrayList list = new ArrayList();

for (String s : items) { list.add(new RowModel(s));

Page 15: Base de Datos en Android

}

setListAdapter(new CheckAdapter(this, list)); selection = (TextView) findViewById(R.id.seleccion); }

private RowModel getModel(int position) { //return (((CheckAdapter) this.getListAdapter()).getItem(position)); return (RowModel)((CheckAdapter)this.getListAdapter()).getItem(position); }

public void onListItemClick(ListView parent, View v, int position, long id) { selection.setText(getModel(position).toString()); }

class CheckAdapter extends ArrayAdapter { Activity context;

CheckAdapter(Activity context, ArrayList list) { super(context, R.layout.fila, list);

this.context = context; }

public View getView(int position, View convertView, ViewGroup parent) { View fila = convertView; ViewWrapper wrapper; CheckBox cb;

if (fila == null) { fila = View.inflate(this.getContext(), R.layout.fila, null); wrapper = new ViewWrapper(fila); fila.setTag(wrapper); cb = wrapper.getCheckBox();

CompoundButton.OnCheckedChangeListener l = newCompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Integer myPosition = (Integer) buttonView.getTag(); RowModel model = getModel(myPosition);

model.isChecked = isChecked; buttonView.setText(model.toString()); } }; cb.setOnCheckedChangeListener(l); } else { wrapper = (ViewWrapper) fila.getTag(); cb = wrapper.getCheckBox(); } RowModel model = getModel(position);

cb.setTag(new Integer(position)); cb.setText(model.toString()); cb.setChecked(model.isChecked); return (fila); } } class RowModel { String label; boolean isChecked = false;

RowModel(String label) { this.label = label; }

public String toString() {

Page 16: Base de Datos en Android

if (isChecked) { return (label.toUpperCase()); }

return (label); } }}

En concreto esto es lo que se ha hecho nuevo: 1. Aunque aun estamos utilizando elementos de un array de String, como la lista de palabras, en lugar de añadir nuestro array de texto directamente en un ArrayAdapter, lo convertimos en una lista de objetos RowModel. Usar RowModel en esta demo es un excusa muy pobre para usar modelos mutables: usando un texto y el estado del check. En un ejemplo real, estos podrían ser objetos mas complejos como un Cursor, y propiedades adaptadas a nuestro negocio. 2. Usamos metodos como onListItemClick() para actualizar el cambio refrejado en el modelo de string que usa el RowModel. 3. La subclase ArrayAdapter (CheckAdapter), en el metodo getView (), comprueba si el convertView es nulo. Si es así, crear una nueva fila con el metodo inflate y también añade la fila sobre el ViewWrapper. Para cada check de la fila añade un evento onCheckedChanged() que comprueba la fila (gettag ()) y que se convierte en un Integer, lo que representa la posición dentro de la ArrayAdapter de la fila que se muestra. Esando esto el checkboxpuede obtener el RowModel actual de la fila y actualizar el modelo basado en el nuevo estado del checkbox. Además, actualiza el texto del ckeckbox en caso que su estado(check/unchecked) coincida con el estado del ckeckbox. 4. Siempre asegúrese de que el checkbox tiene el contenido adecuado y tiene una etiqueta (a través de setTag ()) apuntando a la posición en el adapter de la fila que se muestra. El diseño de la fila es muy simple: sólo un CheckBox dentro de un LinearLayout. fila.xml

Código :

<?xml version="1.0" encoding="utf-8"?><LinearLayoutandroid:id="@+id/listado_filas"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><CheckBox android:id="@+id/check"android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox></LinearLayout>

Posiblemente, nuestro LinearLayout es sencillo, pero puede que se desee complicar mas las filas que con un simple CheckBox, puede que quiera añadir algunos ImageViews con iconos que representan varios tipos de información para cada fila, por ejemplo.

El ViewWrapper es igualmente sencillo, basta con extraer el checkbox fuera de la fila:

Código android:

class ViewWrapper { View base; CheckBox cb=null; ViewWrapper(View base) { this.base=base; }

Page 17: Base de Datos en Android

CheckBox getCheckBox() { if (cb==null) { cb=(CheckBox)base.findViewById(R.id.check); } return(cb); }}

Este código es un poco engorroso. Pero sin duda, se puede simplificar, con el uso del RowModel en la etiqueta contra un Integer, indicandolo como el indice dentro del ArrayAdapter. Además, en un capitulo posterior, vamos a ver cómo se puede envolver la mayor parte de la complejidad hasta en un widget personalizado.

[Manual] Usar hilos y a la vez mostrar una barra de progreso

El ejemplo es muy sencillo pero resulta muy útil así como un recurso bastante bueno.

La idea es realizar cierto trabajo en un hilo, mientras mostramos al usuario una barra de progreso, es decir le indicamos que se están realizando acciones y que debe esperar.

Lo primero es tener una clase que implemente runnable para así poder lanzar hilos. Esto se podría hacer con varías clases ( es solo un ejemplo).

La idea es que al ejecutar la clase se va a realizar lo que pongamos dentro del método run, en nuestro caso está configurado al presionar una tecla. Mientras tanto mostramos la barra de progreso, una vez termine de realizar las tareas en run, entonces podemos parar la barra y seguir con lo que queramos.

El código del ejemplo es el siguiente:

Código :

public class ProgressDialogExample extends Activity implements Runnable { private String prueba; private TextView tv; private ProgressDialog pd; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); tv = (TextView) this.findViewById(R.id.main); tv.setText("Press any key to start calculation"); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { pd = ProgressDialog.show(this, "Working..", "Calculating Pi", true, false); Thread thread = new Thread(this); thread.start(); return super.onKeyDown(keyCode, event); }

Page 18: Base de Datos en Android

public void run() { //Realizar una operación que requiera tiempo prueba = "holaaa"; int aux=0; for(int i = 0 ; i<100000; i++){ aux = aux + 1; aux = (aux * 4000) / 3; } handler.sendEmptyMessage(0); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { pd.dismiss(); tv.setText(prueba); } }; }

[Manual] Enviar SMS y controlar avisos

Pongo aquí un método que se puedew utilizar para enviar mensajes de texto (SMS), únicamente habrá que darle el número de teléfono en un String y el mensaje que le quieras enviar, el mismo método lo cortará y lo enviará.

Además puedes controlar los avisos, está comentado en los huecos para que cada uno ponga la acción que quiera realizar según le convenga.

Código android:

private void sendSMS(String phoneNumber, String message) { String SENT = "SMS_SENT"; String DELIVERED = "SMS_DELIVERED";

//---cuando el SMS ha sido enviado--- registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context arg0, Intent arg1) { switch (getResultCode()) { case Activity.RESULT_OK: //enviado break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: //fallo break; case SmsManager.RESULT_ERROR_NO_SERVICE: //no funciona el servicio break; case SmsManager.RESULT_ERROR_NULL_PDU: //no PDU break; case SmsManager.RESULT_ERROR_RADIO_OFF: //No hay cobertura break; } } }, new IntentFilter(SENT));

//---cuando el SMS ha sido recibido---

Page 19: Base de Datos en Android

registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context arg0, Intent arg1) { switch (getResultCode()) { case Activity.RESULT_OK: //bien recibido break; case Activity.RESULT_CANCELED: //cancelado break; } } }, new IntentFilter(DELIVERED));

SmsManager sms = SmsManager.getDefault();//cortamos el mensaje en trozos pr si fuera más grande de 160 ArrayList<String> smsCut = sms.divideMessage(message); //creamos avisos para cada mensaje enviado ArrayList<PendingIntent> sentPIs = new ArrayList<PendingIntent>(); ArrayList<PendingIntent> deliveredPIs = new ArrayList<PendingIntent>(); for(int i=0; i<smsCut.size(); i++){ sentPIs.add(PendingIntent.getBroadcast(this, i+1, new Intent(SENT), 0)); deliveredPIs.add(PendingIntent.getBroadcast(this, i+1, new Intent(DELIVERED), 0)); } sms.sendMultipartTextMessage(phoneNumber, null, smsCut, sentPIs, deliveredPIs); }

[Manual] Cambiar el locale por codigo para cambio de idioma

Hola, despues de buscar por el foro y no encontrar la manera de cambiar el idioma de la aplicacion por codigo, decidi googlear un poco y encontre un trozo de codigo que espero les sea util a mucha gente del foro, a lo mejor ya estaba por el foro, pero no lo encontre.

Bueno la manera es crear como siempre dos carpetas "values", una quedaria asi: "values" que seria la que contendria el xml de strings por defecto, en nuestro caso en español, y las demas carpetas serian por ejemplo para el ingles : "values-en", y para demas idiomas bastaria con cambiar el "-en" por otro codigo de idioma, que se pueden encontrar en la wikipedia, por ejemplo.

Una vez tengamos las carpetas nombradas es hora de cambiar el Locale por codigo, por ejemplo, si tenemos en nuestro programa un boton de cambio de idioma y este nos lleva a una nueva activity que contenga una vista con botones para diferentes idiomas, o que simplemente el boton nos muestre una vista nueva a parte y en esa vista tengamos los botones, eso ya quedaria a gusto del programador xD.

Pues en los botones de idioma iria el codigo este:

Código :

Locale l = new Locale("en"); Resources resource = this.getResources(); Configuration cf = resource.getConfiguration(); DisplayMetrics dm = resource.getDisplayMetrics(); cf.locale = l; resource.updateConfiguration(cf, dm);

Page 20: Base de Datos en Android

Esto seria para un boton que cambiara el idioma a ingles. Para cambiar a otro idioma basta con crear un locale que contenga el codigo del idioma que queramos.

[Manual] Pasar de una actividad a otra y enviar información

Este código seŕia la llamada desde la primera actividad d¡¡, donde ACTIVIDAD ACTUAL es la clase desde donde se llama (NombreDeLaClase.class, o this, o el contexto), ACTIVIDAD SIGUIENTE sería el nombre de la siguiente clase (NombreDeLaClase.class) e IDENTIFICADOR sería un ejemplo de lo que le podrías pasar, pero puedes ponerle el nombre que quieras y añadir cualquier dato serializable.

Código :

Intent intent = new Intent(ACTIVIDAD ACTUAL,ACTIVIDAD SIGUIENTE );intent.putExtra("id", IDENTIFICADOR);startActivity(intent);

Este código habría que ejecutarlo al inicio de la segunda actividad, en onCreate() por ejemplo, y recoge los datos que le has enviado anteriormente, en este caso al haber añadido un entero hay que poner getInt.

Código :

Bundle bundle = getIntent().getExtras();if(bundle!=null){ id = extras.getInt("id");}

Modificaciones:

Si queremos después recibir datos de la actividad secundaria a la principal haremos llamada de diferente manera Y para recogerla en la actividad principal añadiremos el método onActivityResult que será el que se ejecute al volver a la actividad, donde al recibir el intent anterior podremos recoger en data los datos pasados. El IDENTIFICADOR es un entero que se pone es para indicarle que los datos los querrás recibir en el método onActivityResult y que llevará ese ID que luego se recibirá en requestCode. (El CODIGO RETORNO será el devuelto por la actividad secundaria que genera el resultado, es lo siguiente)

Código :

startActivityForResult(intent, IDENTIFICADOR);

Código :

protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == CODIGO RETORNO && requestCode == IDENTIFICADOR) { TU CÓDIGO

Page 21: Base de Datos en Android

} }

En la actividad secundaria hay que indicarle antes de cerrar que vas a enviar los datos por lo que se hace un setTesult. Además podemos indicar diferente tipo de retorno mediante el CODIGO RETORNO, un entero que se le enviará a la otra actividad.

Código :

setResult(CODIGO RETORNO, intent);

[MANUAL] Como crear preferencias en tu programa

He creado una entrada en mi blog, pero la copia y pego aquí por si a alguien le interesa

Una de las cosas que más me gusta de Android es que te facilita crear muchas de las cosas comunes que necesita una aplicación y para ello suele usar archivos XML. En el caso de las preferencias no iba a ser distinto y en pocos minutos te puedes crear tus preferencias.

Esto tiene dos ventajas:

1. En poco minutos puedes hacer algo que tardarías horas en diseñar 2. Las preferencias tienen un aspecto común en todas las aplicaciones de Android. Así un usuario que esté acostumbrado a usar el sistema estará familiarizado con la pantalla

Ahora vamos a por el código. Para realizar una pantalla de preferencias simplemente tienes que crear una nueva Actividad que herede de PreferenceActivity. Desde el método onCreate vamos a invocar un archivo XML que se encuentra en res/xml y que contiene la estructura, claves y objetos de nuestra pantalla de preferencias. El código sería el siguiente:

Código :

public class PreferencesFromXml extends PreferenceActivity { @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); // Load the preferences from an XML resourceaddPreferencesFromResource(R.xml.preferences);} }

Este código es uno de los ejemplos que viene con el SDK de Google y se encuentra aquí

Una vez hecho esto simplemente tendremos que rellenar nuestro archivo XML. Para ello lo mejor es fijarse en este ejemplo de Google donde se pueden ver como crear grupos de preferencias, listas, checkbox, etc.

Una vez hecho esto nos queda acceder a los contenidos de las preferencias. Lo mejor es que no nos tenemos que preocupar en ningún momento de almacenar la información en ningún lado, de esto se encarga Android.

Page 22: Base de Datos en Android

Lo primero es poner bien todos los "key" en el XML. Cada objeto tiene un atributo llamado "android:key" que nos servirá para poder acceder a él cuando sea necesario.

Para poder trabajar con las preferencias necesitamos un objeto de tipo SharedPreferences que podemos obtener en nuestra actividad de la siguiente forma:

Código :

PreferenceManager.setDefaultValues(this, R.xml.prefer, false);SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this); p.getString("key", "value_default")

Lo primero que tenemos que poner es como "preferencias por defecto" de nuestra actividad el archivo XML que contiene las preferencias. Luego podremos acceder a las preferencias mediante el "key" y los métodos que nos ofrece el objeto SharedPreferences.

Una forma muy cómda de trabajar y fácil de usar. A continuación una imagen de como están quedando las preferencias de mi programa:

Page 23: Base de Datos en Android

[MANUAL] Aplicación sencilla-Forwarding editada

Hola, ya he terminado esta aplicación....y pues a pesar de todo lo que hay en el foro se generaron ciertos errores , debido a esto pongo el código funcional completo ... discúlpenme por no montarlo en un tutorial.....haber si alguien me ayuda y lo sube en pdf.... sino más tarde lo hago yo....

Código en . Java(prueba.java)

Código android:

package android.prueba;

import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;

public class prueba extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.prueba01); Button Boton=(Button)findViewById(R.id.Button01); Boton.setOnClickListener(botonpulsar); } private OnClickListener botonpulsar = new OnClickListener() { public void onClick(View v) { Intent intent = new Intent(); intent.setClass(prueba.this, prueba2.class); startActivity(intent); finish(); } }; }

Código en XML (prueba.XML)

Código XML:

<?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:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /><Button android:text="pulsar" android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button></LinearLayout>

Page 24: Base de Datos en Android

Código en . Java(prueba2.java)

Código android:

package android.prueba;

import android.app.Activity;import android.os.Bundle;

public class prueba2 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.prueba2); }}

Código en XML (prueba2.XML)

Código XML:

<?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:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/nueva" />

</LinearLayout>

Código AndroidManifest.XML

Código XML:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.prueba" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".prueba" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".prueba2" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" />

Page 25: Base de Datos en Android

<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /></manifest>

[MANUAL] Abrir configuración GPS

Publicado: Lun May 25, 2009 9:19 am Título del mensaje: [MANUAL] Abrir configuración GPS

Con el siguiente código podremos abrir la ventana de configuración desde donde activar o desactivar el GPS entre otras cosas.

Recordar que desde la versión 1.5 esta es la forma correcta de cambiar la configuración del dispositivo.

Código :

Intent settingsIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);this.startActivityForResult(settingsIntent, 0);

[Manual] Enviar un E-Mail desde Android

Aquí os dejo un código muy sencillo que sirva para enviar e-mails desde nuestro teléfono.

Código :

Intent sendIntent = new Intent(Intent.ACTION_SEND);sendIntent.putExtra(Intent.EXTRA_TEXT, "email text");sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject");sendIntent.setType("message/rfc822");

startActivity(Intent.createChooser(sendIntent, "Title:"));

Seguramente tengáis problemas para probarlo desde el emulador puesto que no viene con ningún cliente de correo electrónico instalado.

Lo más seguro es que os dé el siguiente mensaje:

Cita:

No Applications can perform this action

Es necesario tener un G1 para probarlo bien, si alguno es afortunado y tiene uno que nos diga si de verdad funciona.

Aquí os dejo la lista de constantes que podemos utilizar:

Page 26: Base de Datos en Android

EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC, EXTRA_SUBJECT

http://code.google.com/android/reference/android/content/Intent.html

Saludos.

[Manual] Crear una aplicación con mapas Parte 1

Hola a todos:

Bueno lo que vamos a ver aquí es como empezar a crear una aplicación que muestre los mapas de google, parecido al que viene con el emulador pero de momento mucho más simple.

En el primer capitulo y para no aburriros simplemente vamos a ver lo sencillo que es mostrar un mapa.

public class MyApp extends MapActivity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle);

//creamos una vista de mapa MapView MV = new MapView(this); //creamos un controlador de ese mapa MapController MC = MV.getController(); //Especificamos el zoom con el que lo vamos a mostrar MC.zoomTo(15);

//Unas coordenadas, latitud longitud en gratos * 10^6 Point point = new Point(48811100, 2328000); //centramos la vista del mapa en este punto MC.centerMapTo(point, true);

//le decimos que lo muestre setContentView(MV); }

}

Bueno como veis es muy fácil empezar. Esto es sólo el principio de lo que será nuestra aplicación, de momento empezar a trastear con esto.

[Manual] para crear una aplicación con mapas Parte 2

Hola a todos de nuevo:

Hoy vamos a seguir con el manual para crear aplicaciones con mapas. En el capitulo 1 vimos lo que hacía falta para mostrar el mapa por pantalla, así como poder asignarle un controlador a ese mapa y realizar distintas acciones sobre él.

En la segunda parte lo que vamos a ver es como asignar ciertas acciones a distintas teclas,

Page 27: Base de Datos en Android

así cuando pulsemos una tecla en nuestro dispositivo debería realizar acciones sobre el mapa.

Lo primero es crearnos un nuevo método que se llame

" public boolean onKeyDown(int keyCode, KeyEvent event) "

Lo fundamental del método es saber que tecla se ha pulsado, para ello usaremos lo siguiente:

" if (keyCode == KeyEvent.KEYCODE_I) "

Con esto casi ya lo tenemos, falta poco. Voy a explicar que habria que poner para que al pulsar la tecla I que es a la que corresponde el código que hemos puesto, hicieramos zoom en el mapa.

int level = mMapView.getZoomLevel(); MV.getController().zoomTo(level + 1); return true;

Lo primero que hacemos es conseguir el nivel de zoom actual para poder sumarle o restarle un nivel, depende di si queremos alejar o acercar la vista en el mapa.

MV se corresponde con la vista del mapa que creamos en el capitulo 1.

A continuación os dejo el código completo por si habéis perdido. Las acciones que están asignadas son, las dos del zoom, activar la vista del satélite y activar la vista de la capa de tráfico.

Espero que os sirva de ayuda.

En el siguiente capitulo veremos como dibujar marcas de sitios en el mapa, así como conseguir mostrar información sobre los mismos.

Nos vemos en el sigueinte capitulo.

/* Controlamos las acciones que se llevan a cabo, según que * tecla hemos pulsado. */ public boolean onKeyDown(int keyCode, KeyEvent event) { // Zoom In if (keyCode == KeyEvent.KEYCODE_I) { // miramos que zoom hay, y le sumamos uno. int level = mMapView.getZoomLevel(); MV.getController().zoomTo(level + 1); return true; } //Zoom Out else if (keyCode == KeyEvent.KEYCODE_O) { int level = mMapView.getZoomLevel(); MV.getController().zoomTo(level - 1); return true; } //Activar/Desactivar la vista de satelite

Page 28: Base de Datos en Android

else if (keyCode == KeyEvent.KEYCODE_S) { MV.toggleSatellite(); return true; } //Activar la capa de trafico else if (keyCode == KeyEvent.KEYCODE_T) { MV.toggleTraffic(); return true; } return false; }

[Manual] Android en netbeans

1º Paso.

Debemos bajar el siguiente archivo: - org-netbeans-modules-android-platform.nbm, (39.57kB)

2º Paso.

Page 29: Base de Datos en Android

3º Paso.

Page 30: Base de Datos en Android

4º Paso.

Page 31: Base de Datos en Android

5º Paso.

Page 32: Base de Datos en Android

6º Paso.

Page 33: Base de Datos en Android

7º Paso.

Page 34: Base de Datos en Android
Page 35: Base de Datos en Android
Page 36: Base de Datos en Android
Page 37: Base de Datos en Android

Gracias a Apache.

Guia Android: Avanzando con la base de datos

En el primer tutorial sobre Android hicimos el típico Hello World, explicando la

estructura de Android, cómo funcionaba ese básico ejemplo. En este segundo

tutorial vamos a meternos en muchos más detalles. Vamos a construir un bloc

de notas para nuestro teléfono Android. Debido a que son más archivos y más

líneas de código que en el primer ejercicio os he comprimido los archivos

iniciales y finales en un archivo zip (Descargar). Asi siempre tenéis código

dónde comparar por si no os funciona algo. Pero como siempre, es mejor que

vayáis siguiendo el tutorial y veáis la evolución del código en vez de mirar

directamente la solución.

Page 38: Base de Datos en Android

Conexión a la base de datosUna vez que habéis creado el proyecto Android seleccionando un proyecto

existente (Notas), podéis ver la estructura de archivos. Hay ya algunos archivos

creados pero el único que he dejado con información

es /src/com.android.demo.notepad1/NotasDbAdapter.java. Este archivo se va a

encargar de conectarse a la base de datos para que no tengamos que estar

lidiando con esto en otras partes del código. Recordad que estamos en un

esquema MVC. Este va a ser nuestro primer modelo. Miremos el código en

general:01 public class NotasDbAdapter {

02 03 // variables varias

04 ...

05

06 private static class DatabaseHelper extends SQLiteOpenHelper {

07 08 DatabaseHelper(Context context) {09 super(context, DATABASE_NAME, null, DATABASE_VERSION);

10 }

11 12 @Override

13 public void onCreate(SQLiteDatabase db) {...}

14

15 @Override

16 public void onUpgrade(SQLiteDatabase db, int oldVersion,int newVersion) {...}

17 }

18

19 /**

20 * Constructor - pasa el contexto para poder abrir o crear la DB

21 */

22 public NotasDbAdapter(Context ctx) {...}

23 24 /**

25 * Abre la base de datos de notas. Si no puede abrirla, la crea. Si no se puede

26 * lanza una excepcion

Page 39: Base de Datos en Android

27 */

28 public NotasDbAdapter open() throws SQLException {...}

29

30 public void close() {...}

31 32 /**

33 * Inserta una nueva nota con el t’tulo y el texto dados. Si se crea correctamente

34 * devuelve el rowId, en caso contrario, devuelve -1 para indicar que ha habido

35 * un error..

36 */

37 public long createNote(String title, String body) {...}

38

39 /**

40 * Borra la nota con el rowId dado

41 */

42 public boolean deleteNote(long rowId) {...}

43 44 /**45 * Devuelve un Cursor apuntando a la lista de todas las notas

46 */

47 public Cursor fetchAllNotes() {...}

48

49 /**

50 * Devuelve un Cursor apuntando a la nota con el rowId dado

51 */

52 public Cursor fetchNote(long rowId) throws SQLException {...}

53 54 /**55 * Actualiza la nota con los detalles dados.

56 */

57 public boolean updateNote(long rowId, String title, String body) {...}

58 }

Tenemos métodos para crear, actualizar, abrir y cerrar la base de datos. Y luego

los métodos CRUD para crear una nueva nota, devolver su información (o la de

varias notas), actualizarla y borrarla. Esta clase es muy importante ya que

Page 40: Base de Datos en Android

estará en todas vuestras apps de una forma u otra asi que miremos método a

método.

01 private static class DatabaseHelper extends SQLiteOpenHelper {

02

03 DatabaseHelper(Context context) {

04 super(context, DATABASE_NAME, null, DATABASE_VERSION);05 }

06

07 @Override

08 public void onCreate(SQLiteDatabase db) {09 db.execSQL(DATABASE_CREATE);

10 }

11 12 @Override

13 public void onUpgrade(SQLiteDatabase db, int oldVersion, intnewVersion) {

14 Log.w(TAG, "Upgrading database from version " + oldVersion + " to "

15 + newVersion + ", which will destroy all old data");

16 // sentencia drop

17 onCreate(db);

18 }

19 }

Esta clase auxiliar nos permitirá abrir la base de datos, crearla si no existe y

actualizarla al lanzar una nueva versión. La sentencia SQL para crear es:

// sentencia create

1private static final String DATABASE_CREATE = "create table notes (_id integer primary key autoincrement," + "title text not null, body text not null);";

Cómo podéis haber observado ya antes, estamos utilizando la base de datos

SQLite, es parecida a MySQL pero tiene pequeños detalles diferentes. Con esto

ya tenemos creada la base de datos. Veamos el método para insertar notas:

1 public long createNote(String title, String body) {

2 ContentValues initialValues = new ContentValues();3 initialValues.put(KEY_TITLE, title);

Page 41: Base de Datos en Android

4 initialValues.put(KEY_BODY, body);

5

6 return mDb.insert(DATABASE_TABLE, null, initialValues);7 }

A través de la clase ContentValues guardamos la información con el método put

y la insertamos. Para actualizar es casi igual pero usamos el método update en

vez de insert. Hay que acordarse de indicar el rowId:

1 public boolean updateNote(long rowId, String title, String body) {

2 ContentValues args = new ContentValues();3 args.put(KEY_TITLE, title);

4 args.put(KEY_BODY, body);

5

6 return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) &gt; 0;

7 }

El método borrar es muy obvio asi que pasamos a recuperar una nota de la

base de datos:

01 public Cursor fetchNote(long rowId) throws SQLException {

02 03 Cursor mCursor =

04

05 mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,

06 KEY_TITLE, KEY_BODY}, KEY_ROWID + "=" + rowId,null,

07 null, null, null, null);

08 if (mCursor != null) {09 mCursor.moveToFirst();

10 }

11 return mCursor;

12 13 }

Hacemos una query indicando que queremos un array de tres strings con los

tres campos que queremos, y con la condición de rowId. El resto de los

parámetros se usan si queremos hacer groupBy, having u orderBy. Después

Page 42: Base de Datos en Android

comprobamos que no está vacío y si es así movemos el cursor a la primera

posición que apunta a la nota que queremos.

Insertando notasVamos a modificar el layout de la actividad inicial /res/layout/notepad_list.xml

01 &lt;?xml version="1.0" encoding="utf-8"?&gt;

02&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

03 android:layout_width="wrap_content"

04 android:layout_height="wrap_content"&gt;

05 06 &lt;ListView android:id="@android:id/list"

07 android:layout_width="wrap_content"

08 android:layout_height="wrap_content"/&gt;09 &lt;TextView android:id="@android:id/empty"

10 android:layout_width="wrap_content"

11 android:layout_height="wrap_content"12 android:text="@string/no_notes"/&gt;

13 14 &lt;/LinearLayout&gt;

Tenemos dos elementos: una lista y un campo de texto. El TextView sólo se

muestra si la lista está vacía. Android sabe esto gracias a empty, que está unido

al valor de list. A través deandroid:id="@android:id/list" indicamos que

queremos que esa lista se rellene con los valores de la variable list de la

actividad.

Para mostrar la información que aparece en cada fila de la lista necesitamos

crear un nuevo template. Creamos un nuevo archivo /src/layout/notes_row.xml1 &lt;?xml version="1.0" encoding="utf-8"?&gt;

2 &lt;TextView android:id="@+id/text1"

3 xmlns:android="http://schemas.android.com/apk/res/android"

4 android:layout_width="wrap_content"

5 android:layout_height="wrap_content"/&gt;

En el campo de texto (TextView) vamos a mostrar solo el contenido de la

variable text1 de la actividad. Antes de ir a la actividad mirad la clase R.java

que os dije en el anterior tutorial que Android la manejaba automáticamente.

Podéis ver cómo ha añadido el archivo nuevo y la variable text1.

Vayamos ahora con Notas.java, miremos su estructura:1 public class Notas extends Activity {

Page 43: Base de Datos en Android

2

3 public void onCreate(Bundle savedInstanceState) {...}

4

5 public boolean onCreateOptionsMenu(Menu menu) {...}

6

7 public boolean onOptionsItemSelected(MenuItem item) {...}

8 }

onCreate() es el método principal de la actividad donde ejecutaremos todo

nuestro código.onCreateOptionsMenu() creará el menú de opciones

y onOptionsItemSelected() estará atento a qué botón del menú presionamos

para ejecutar la acción correspondiente. Repito que es sólo sobre acciones

sobre el menú, las acciones de otros botones o enlaces van en otros métodos,

exactamente con Listeners, pero eso ya lo veremos más adelante.

Lo primero que vamos a hacer es convertir a Notas en una actividad de lista,

para ellos hacemos que extienda a ListActivity:

1 public class Notas extends ListActivity

Una combinación de teclas muy útil para arreglar los imports de los paquetes es

ctrl-shift-O en Windows o Linux, o cmd-shift-O en el Mac.

Queremos que en la pantalla principal de Notas muestre la lista de notas, para

ello tiene que conectarse a la base de datos, coger la información y mostrarla

en el layout que hemos hecho antes:

01 private NotasDbAdapter mDbHelper;

02

03 @Override

04 public void onCreate(Bundle savedInstanceState) {

05 super.onCreate(savedInstanceState);

06 setContentView(R.layout.notepad_list);

07 // new notas

08 mDbHelper.open();09 fillData();

10 }

Page 44: Base de Datos en Android

Declaramos el objeto fuera para que esté disponible a todos los métodos,

fijamos que el layout sea notepad_list (fijaros como referenciamos aquí al

layout, no usamos urls o directorios, si no referencia mediante la clase R.java).

Vamos a coger la información en un método privado para que quede todo más

ordenado:

01 private void fillData() {

02 // Recuperamos todas las notas de la DB y creamos una lista Cursor

03 c = mDbHelper.fetchAllNotes();

04 startManagingCursor(c);

05

06 String[] from = new String[] { NotasDbAdapter.KEY_TITLE };07 int[] to = new int[] { R.id.text1 };

08 09 / Y creamos un adaptador array para que vaya mostrando las filas

10 SimpleCursorAdapter notes =

11 new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);

12 setListAdapter(notes);

13 }

Ya empezamos a ver más métodos internos de Android, os animo a entrar a la

API de Android e ir viendo lo que hacen exactamente, es la mejor forma de

aprender. En fillData()recuperamos todas las notas de la DB con el método

fetchAllNotes que hicimos al principio, y luego creamos un adaptador que

relaciona el campo del objeto que queremos (KEY_TITLE) con la

variable text1 (otra vez referenciada por R.java) e indica que queremos que use

el layout notes_row.xml que hemos creado antes. Por último avisa

a ListActivity que notes va a ser la lista que queremos mostrar.

Con estas modificaciones ya podríamos ver las notas pero no tenemos ninguna

asi que vamos a crear la actividad en un momento para que podamos probarlo

más a fondo. EnNotas.java añadamos el botón de añadir nota. Basta con llamar

a la clase superior para crear el menu y añadir el botón de Add Item en la

primera posición.1 public static final int INSERT_ID = Menu.FIRST;

2

3 @Override

4 public boolean onCreateOptionsMenu(Menu menu) {

Page 45: Base de Datos en Android

5 boolean result = super.onCreateOptionsMenu(menu);

6 menu.add(0, INSERT_ID, 0, R.string.menu_insert);

7 return result;

8 }

Y añadimos otra variable de texto a strings.xml

1 &lt;string name="menu_insert"&gt;Add Item&lt;/string&gt;

Perfecto, ahora hagamos que al hacer click en este nuevo botón ejecute la

nueva actividad para mostrar el formulario. Para eso modificamos el

método onOptionsItemSelected() también de Notas.java

01 @Override

02 public boolean onOptionsItemSelected(MenuItem item) {03 switch (item.getItemId()) {

04 case INSERT_ID:05 createNote();

06 return true;07 }

08

09 return super.onOptionsItemSelected(item);

10 }

Capturamos el Id de la opción del menú y si es la primera ejecutamos el

método createNote(). En un primer paso vamos a hacer que inserte una nota

con un título y texto fijos. En el siguiente paso ya crearemos el formulario:

1 private void createNote() {

2 String noteName = "Note " + mNoteNumber++;3 mDbHelper.createNote(noteName, "");

4 fillData();

5 }

La razón de llamar a fillData() de nuevo es para que recargue la lista una vez

que se ha terminado de ejecutar el evento de hacer click en la opción del menú

Add Item.

Es hora de ver en acción lo que estamos viendo. Comprueba que no hay errores

en ningún archivo, arregla los imports y ejecuta como un proyecto de Android.

Si das a menu podrás añadir una nota e irás viendo como se crea una nota

nueva cada vez que le das. Enhorabuena, hemos conseguido comunicarnos

correctamente con la base de datos.

Page 46: Base de Datos en Android

Creando la nota con el formulario

Lo que queremos ahora es que cuando hacemos click en Add Item vayamos a

otra pantalla donde podamos escribir el título y el texto de la nota. Demos a

guardar y aparezca en la lista de notas. Para eso vamos a tener que crear otra

actividad (pantalla-controlador). Pensad que por cada pantalla que queramos

tener vamos a tener que tener una nueva actividad.

Antes de eso vamos a permitir borrar notas, para ello vamos a Notas.java.

Añadimos la siguiente línea al final del método onCreate()1 registerForContextMenu(getListView());

Queremos que al hacer click en un elemento de lista nos salga un menú desde

donde podamos borrarlo. Añadimos un nuevo método que sobreescribe a uno

de Android:

1 @Override

2 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

3 super.onCreateContextMenu(menu, v, menuInfo);

4 menu.add(0, DELETE_ID, 0, R.string.menu_delete);5 }

Hace falta insertar más variables en Notas.java1 private static final int ACTIVITY_CREATE=0;

2 private static final int ACTIVITY_EDIT=1;

3

4 private static final int INSERT_ID = Menu.FIRST;5 private static final int DELETE_ID = Menu.FIRST + 1;

y en strings.xml1 &lt;string name="menu_delete"&gt;Delete Note&lt;/string&gt;

2 &lt;string name="title"&gt;Title&lt;/string&gt;

3 &lt;string name="body"&gt;Body&lt;/string&gt;

4 &lt;string name="confirm"&gt;Confirm&lt;/string&gt;5 &lt;string name="edit_note"&gt;Edit Note&lt;/string&gt;

Ahora que ya podemos seleccionar la nota a borrar, vamos a crear el método

que efectivamente lo borra:

01 @Override

Page 47: Base de Datos en Android

02 public boolean onContextItemSelected(MenuItem item) {03 switch(item.getItemId()) {

04 case DELETE_ID:

05 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

06 mDbHelper.deleteNote(info.id);

07 fillData();

08 return true;

09 }

10 return super.onContextItemSelected(item);11 }

Volvemos a hacer un switch para comprobar la posición del botón del menú y si

es la segunda borramos la nota y recargamos la lista. Conseguimos el ID de la

nota gracias a getMenuInfo()y al método registerForContextMenu() que hemos

insertado antes al final de onCreate().

Volvamos ahora al método auxiliar para crear nuevas notas, borramos lo que

teníamos y vamos a cargar una nueva actividad:

1 private void createNote() {

2 Intent i = new Intent(this, NoteEdit.class);3 startActivityForResult(i, ACTIVITY_CREATE);

4 }

Lo que hacemos es crear un nuevo Intent, una nueva actividad, en este caso

NoteEdit que todavía no hemos creado. Ejecuta su comienzo y espera el

resultado. Con el resultado luego llamará a la función onActivityResult() que

implementaremos más tarde. Si no nos interesa saber el resultado basta con

llamar a la función startActivity()

Vamos a hacer algo parecido para editar las notas que ya tenemos. Pero antes

de nada vamos a permitir utilizar el Cursor en toda la clase, para eso añadimos

la variable de clase:

1 private Cursor mNotesCursor;

refactorizamos onCreate() que quedaría ahora así:

1 @Override

2 public void onCreate(Bundle savedInstanceState) {

3 super.onCreate(savedInstanceState);

Page 48: Base de Datos en Android

4 setContentView(R.layout.notepad_list);

5 mDbHelper = new NotasDbAdapter(this);

6 mDbHelper.open();

7 fillData();

8 registerForContextMenu(getListView());9 }

y nuestro método privado fillData()

01 private void fillData() {02 // Recupera todas las notas de la DB y las guarda en el cursor03 mNotesCursor = mDbHelper.fetchAllNotes();

04 startManagingCursor(mNotesCursor);

05 06 // Array con los campos que queremos mostrar en la lista

07 String[] from = new String[]{NotasDbAdapter.KEY_TITLE};

08 09 // array con las variables asociadas para esos campos

10 int[] to = new int[]{R.id.text1};

11 12 SimpleCursorAdapter notes =

13 new SimpleCursorAdapter(this, R.layout.notes_row, mNotesCursor, from, to);

14 setListAdapter(notes);

15 }

Ahora ya podemos fijarnos en el método que se ejecute al hacer click sobre un

elemento de la lista. Se llama onListItemClick() y lo sobreescribimos:

01 @Override

02protected void onListItemClick(ListView l, View v, int position,long id) {

03 super.onListItemClick(l, v, position, id);

04 Cursor c = mNotesCursor;

05 c.moveToPosition(position);

06 Intent i = new Intent(this, NoteEdit.class);

07 i.putExtra(NotasDbAdapter.KEY_ROWID, id);

08 i.putExtra(NotasDbAdapter.KEY_TITLE, c.getString(09 c.getColumnIndexOrThrow(NotasDbAdapter.KEY_TITLE)));

10 i.putExtra(NotasDbAdapter.KEY_BODY, c.getString(

11 c.getColumnIndexOrThrow(NotasDbAdapter.KEY_BODY)));

12 startActivityForResult(i, ACTIVITY_EDIT);

13 }

Page 49: Base de Datos en Android

Lo que estamos haciendo es mover el Cursor a la posición en la que estamos,

crear el Intent y pasarle como argumentos el Id, título y texto. Para pasar como

argumentos utilizamos la función putExtra(). Otra función muy útil. Por último lo

ejecutamos esperando el resultado.

Va siendo hora de implementar el método onActivityResult() que es el que se

ejecuta cuando recibimos el resultado de haber creado o editado una nota

con startActivityForResult()

01 @Override

02 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

03 super.onActivityResult(requestCode, resultCode, intent);

04 Bundle extras = intent.getExtras();

05 06 switch(requestCode) {

07 case ACTIVITY_CREATE:08 String title = extras.getString(NotasDbAdapter.KEY_TITLE);09 String body = extras.getString(NotasDbAdapter.KEY_BODY);

10 mDbHelper.createNote(title, body);

11 fillData();

12 break;

13 case ACTIVITY_EDIT:14 Long mRowId = extras.getLong(NotasDbAdapter.KEY_ROWID);

15 if (mRowId != null) {

16 String editTitle = extras.getString(NotasDbAdapter.KEY_TITLE);

17 String editBody = extras.getString(NotasDbAdapter.KEY_BODY);

18 mDbHelper.updateNote(mRowId, editTitle, editBody);

19 }

20 fillData();21 break;

22 }

23 }

Si estamos creando la nota, la guarda en la base de datos. Si la estamos

editando, la actualiza y en ambos casos recarga la lista de notas.

Page 50: Base de Datos en Android

Ya tenemos la lógica más o menos, vamos ahora a crear el layout del

formulario. Para eso creamos el archivo /res/layout/note_edit.xml y lo

rellenamos con:01 &lt;?xml version="1.0" encoding="utf-8"?&gt;

02

03&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

04 android:orientation="vertical" android:layout_width="fill_parent"

05 android:layout_height="fill_parent"&gt;

06 07 &lt;LinearLayout android:orientation="horizontal"

08 android:layout_width="fill_parent"

09 android:layout_height="wrap_content"&gt;

10 11 &lt;TextView android:layout_width="wrap_content"

12 android:layout_height="wrap_content"

13 android:text="@string/title" /&gt;

14 &lt;EditText android:id="@+id/title"

15 android:layout_width="wrap_content"

16 android:layout_height="wrap_content"17 android:layout_weight="1"/&gt;

18 &lt;/LinearLayout&gt;

19 20 &lt;TextView android:layout_width="wrap_content"21 android:layout_height="wrap_content"

22 android:text="@string/body" /&gt;

23 &lt;EditText android:id="@+id/body" android:layout_width="fill_parent"

24 android:layout_height="wrap_content"

25 android:layout_weight="1"

26 android:scrollbars="vertical" /&gt;

27 28 &lt;Button android:id="@+id/confirm"

29 android:text="@string/confirm"

30 android:layout_width="wrap_content"31 android:layout_height="wrap_content" /&gt;

32 33 &lt;/LinearLayout&gt;

Page 51: Base de Datos en Android

Este es un layout ya más complicado. Lo que hace es crear dos campos de

texto, uno para el título y otro para el texto; y el botón que guarda lo que

hemos escrito. Utilizando una mezcla de configuraciones de alturas

conseguimos la apariencia que queremos. En el próximo tutorial entraremos

más en detalle en los layouts.

Vamos a crear la clase NoteEdit.java ahora que ya tenemos su layout. Voy a

copiar el código final comentado y explico detalles al final:

01 /*

02 * Copyright (C) 2008 Google Inc.03 */

04

05 package com.android.demo.notepad1;

06

07 import android.app.Activity;

08 import android.content.Intent;09 import android.os.Bundle;10 import android.view.View;

11 import android.widget.Button;

12 import android.widget.EditText;

13

14 public class NoteEdit extends Activity {

15

16 private EditText mTitleText;17 private EditText mBodyText;

18 private Long mRowId;

19 20 @Override

21 protected void onCreate(Bundle savedInstanceState) {

22 super.onCreate(savedInstanceState);

23 24 // Fijamos el layout de esta actividad25 setContentView(R.layout.note_edit);

26 27 // Objetos que referencian a los campos editables del layout

28 mTitleText = (EditText) findViewById(R.id.title);

29 mBodyText = (EditText) findViewById(R.id.body);

Page 52: Base de Datos en Android

30 Button confirmButton = (Button) findViewById(R.id.confirm);

31 32 // Si hay argumentos, los cogemos

33 mRowId = null;

34 Bundle extras = getIntent().getExtras();

35 if (extras != null) {

36 String title = extras.getString(NotasDbAdapter.KEY_TITLE);

37 String body = extras.getString(NotasDbAdapter.KEY_BODY);

38 mRowId = extras.getLong(NotasDbAdapter.KEY_ROWID);

39

40 // Insertamos los valores actuales de la nota en los campos

41 if (title != null) {42 mTitleText.setText(title);

43 }

44 if (body != null) {45 mBodyText.setText(body);

46 }

47 }

48

49 // Listener para el botón de confirmar

50 confirmButton.setOnClickListener(new View.OnClickListener() {

51

52 public void onClick(View view) {53 Bundle bundle = new Bundle();

54

55 // Guardamos los nuevos valores en un Bundle

56 bundle.putString(NotasDbAdapter.KEY_TITLE, mTitleText.getText().toString());

57 bundle.putString(NotasDbAdapter.KEY_BODY, mBodyText.getText().toString());

58 if (mRowId != null) {

59 bundle.putLong(NotasDbAdapter.KEY_ROWID, mRowId);

60 }

61

62 // y los mandamos de vuelta al método que los está esperando

63 Intent mIntent = new Intent();

Page 53: Base de Datos en Android

64 mIntent.putExtras(bundle);

65 setResult(RESULT_OK, mIntent);

66 finish();

67 }

68 69 });

70 }

71 }

Hay que fijarse en cómo cogemos la referencia al campo de texto (mediante la

clase R.java por supuesto)

mTitleText = (EditText) findViewById(R.id.title);

En cómo cogemos los argumentos que hemos pasado antes con el

método putExtra()

y cómo asignamos los valores actuales

mTitleText.setText(title);

El último paso tras crear una nueva actividad es declararla en el

archivo AndroidManifest.xml. Recordarlo bien porque es un típico fallo que nos

hace perder muchas horas.1 &lt;activity android:name=".NoteEdit"&gt;&lt;/activity&gt;

También se puede introducir la nueva actividad con los paneles de control en

vez de directamente sobre el código (Application -> Add Application Node ->

Activity y rellenamos el nombre)

Es hora de ejecutar el programa de nuevo para ir viendo cómo evoluciona. Ya

podemos editar las notas que creamos antes y crear nuevas con la opción Add

Item del menú. Probad a dar hacia atrás cuando estéis en el formulario. Veréis

cómo salta una excepción.

Resumen

Hoy hemos tocado muchos temas y muy variados:

Page 54: Base de Datos en Android

• Hemos creado nuestro primer modelo con su conexión a la base de datos

(adaptador de por medio para facilitarnos la vida).

• Hemos visto más layouts para mostrar listas y formularios.

• Hemos creado una actividad de lista que os puede servir de modelo para

vuestras apps. Permite crear nuevas notas, editarlas y borrarlas. Aunque

mejor esperad a la semana que viene para tomarla como modelo ya que

haremos algunos cambios importantes.

• Hemos creado una segunda actividad por lo que ya podemos decir que

nuestra app es medianamente compleja, al menos tiene 2 pantallas!

Guía Android: Descubriéndolo con el Hello World

Vamos a empezar en Maestros del Web una serie de artículos más técnicos

sobre cómo hacer aplicaciones para Android, el sistema operativo móvil de

Google. Como sabéis es de código abierto y gratuito por lo que cualquier

persona o empresa pueda cogerlo, modificarlo y usarlo en sus productos. Esta

apertura va a provocar que haya más de 20 móviles con Android a finales de

año.

Incluso recientemente hemos visto que Acer va a lanzar un netbook con una

versión modificada de Android. Por si faltan excusas para aprender también

deciros que Ubuntu ha financiado un proyecto que permitirá ejecutar

programas de Android en este famoso sistema operativo.

Requisitos• Android está hecho en Java+XML, siguiendo el patrón MVC (Model-View-

Controller).

• Bájate el SDK

• El mejor IDE para programar para Android es Eclipse (multiplataforma),

pero puedes usar el que quieras, solo que tendrás menos facilidades. En los

artículos usaremos Eclipse.

• Bájate el plugin de Android para Eclipse (ADT).

En estas fáciles instrucciones podrás completar los pasos previos.

Creando un nuevo proyecto

Page 55: Base de Datos en Android

La mejor forma de conocer un sistema es probándolo asi que vamos a crear el

proyecto y por el camino vamos explicando cómo funciona Android.

Una vez instalado el plugin, creamos el nuevo proyecto de Android (File > New

> Project > Android Project). Damos a siguiente:

Page 56: Base de Datos en Android

• Project name: HolaMundo

• Package name: com.example.holamundo

• Create Activity: HolaMundo

• Application name: Hola Mundo

Aunque he puesto los mismos nombres en los 4 sitios no tiene por qué coincidir,

como sabréis. El nombre de la aplicación es lo que veréis en el móvil, las

actividades son los controladores de Android, el nombre del paquete es algo

interno y el proyecto es lo que veréis en Eclipse. Finalizamos y podremos ver el

siguiente árbol de archivos

Voy a explicar la estructura:

• /src – Aquí se encuentran las actividades (controladores recuerdo), clases

y un archivo que se llama R.java. Este archivo no se debe tocar nunca,

Android lo actualiza automáticamente pero si lo veis os encontraréis con

variables y posiciones.

• /Android Library – Eclipse referencia al sdk de Android. No mováis nunca

el sdk de sitio o si lo hacéis recordad cambiar la dirección

• /assets – Aquí se puede incluir archivos varios (música, pdfs, zips, rars)

• /res/drawable – Todas las imágenes van en este directorio

• /res/layout – Todas las vistas van aquí

Page 57: Base de Datos en Android

• /res/values – En el archivo strings.xml podemos poner variables que

luego sustituiremos en las vistas

• AndroidManifest.xml – Este archivo es muy importante porque recoge

todas las actividades y algunas configuraciones del proyecto.

Antes de seguir vamos a ejecutar el proyecto, y para eso damos a Run As y

elegimos Android Application. Si instalasteis todo bien saldrá el emulador,

cargando iniciando Android (tarda un poquito). Lo desbloqueamos dando a

Menú, y ya puedes ver la aplicación más básica que se hace en todos los

lenguajes, nuestro Hola Mundo.

Page 58: Base de Datos en Android

Si quieres puedes investigar los programas que trae el emulador, está bastante

bien conseguido; aunque para mi gusto faltan varios detalles como girar el

teléfono en posición horizontal. A continuación veremos cómo ha funcionado el

programa.

Entendiendo el Hola Mundo

Gracias al plugin de Android, no hemos programado nada y ya tenemos el

programa básico. Pero como hemos visto antes en la estructura, se han creado

unos cuantos archivos. Vamos a ir paso a paso por cada uno de ellos.

01 // AndroidManifest.xml

02 &lt;?xml version="1.0" encoding="utf-8"?&gt;

03&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"

04 package="com.example.holamundo"

05 android:versionCode="1"

06 android:versionName="1.0.0"&gt;

07 &lt;application android:icon="@drawable/icon" android:label="@string/app_name"&gt;

08 &lt;activity android:name=".HolaMundo"

09 android:label="@string/app_name"&gt;

10 &lt;intent-filter&gt;

11 &lt;action android:name="android.intent.action.MAIN" /&gt;

12 &lt;category android:name="android.intent.category.LAUNCHER" /&gt;

13 &lt;/intent-filter&gt;

14 &lt;/activity&gt;

15 &lt;/application&gt;

16 &lt;/manifest&gt;

Supongo que estaréis familiarizados con xml, si no, no os preocupéis, es muy

fácil de entender. Podemos ver como crea un manifesto con el paquete y la

versión de Android. Contiene la aplicación que hemos

creado. android:icon="@drawable/icon" coge la imagen llamada icon.png del

directorio /res/drawables y la asigna como icono. Esto es lo que véis en el menú

de aplicaciones. Lo mismo sucede conandroid:label="@string/app_name",

sustituye la variable app_name por su valor en el archivo:

1 // res/values/strings.xml

2 &lt;?xml version="1.0" encoding="utf-8"?&gt;

Page 59: Base de Datos en Android

3 &lt;resources&gt;

4 &lt;string name="hello"&gt;Hello World, HolaMundo&lt;/string&gt;5 &lt;string name="app_name"&gt;Hola Mundo&lt;/string&gt;

6 &lt;/resources&gt;

Volviendo a AndroidManifest.xml, vemos que dentro de application se

encuentra la actividad principal android:name=".HolaMundo", que corresponde

con un punto más el nombre de la clase java en src/com.example.holamundo.

El resto son detalles más profundos. Asi que Android ejecuta esa clase, vamos a

verla:01 // src/com.example.holamundo/HolaMundo.java

02 package com.example.holamundo;

03 04 import android.app.Activity;05 import android.os.Bundle;

06

07 public class HolaMundo extends Activity {

08 /** Called when the activity is first created. */

09 @Override

10 public void onCreate(Bundle savedInstanceState) {

11 // Inicializa la actividad

12 super.onCreate(savedInstanceState);

13 // Asignamos la vista

14 setContentView(R.layout.main);15 }

16 }

Crea una actividad llamada HolaMundo con un único método que sobreescribe

al de la clase que extiende. Vemos como setContentView pasa como

parámetro R.layout.main que representa a /res/layout/main.xml. Pero como dije

antes, todo las referencias a archivos y variables pasan por la clase R.java que

Android se encarga de ajustar automáticamente. Veamos la vista

01 // res/layout/main.xml

02 &lt;?xml version="1.0" encoding="utf-8"?&gt;

03&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

04 android:orientation="vertical"

05 android:layout_width="fill_parent"

06 android:layout_height="fill_parent"

07 &gt;

Page 60: Base de Datos en Android

08 &lt;TextView

09 android:layout_width="fill_parent"

10 android:layout_height="wrap_content"11 android:text="@string/hello"

12 /&gt;

13 &lt;/LinearLayout&gt;

Como podéis ver vuelve a ser un xml y es que Google ha elegido usar xml para

representar las vistas. LinearLayout es un tipo de layout que muestra los

elementos uno debajo de otro. Tiene orientación vertical y ocupa toda la

pantalla tanto a lo alto como a lo ancho.

Dentro podemos ver un campo de texto (TextView) cuyo texto se encuentra en

el archivostrings.xml visto antes.

Finalizando

Hemos visto paso por paso lo que hace Android para ejecutar un sencillo Hola

Mundo. Lo importante es:

• AndroidManifest.xml contiene todas las actividades indicando cuál se

ejecuta primero.

• Todas las actividades y clases se encuentran en src. La actividad

HolaMundo usa el layout main.xml

• Todos los layouts están en res/layout. Se programan en xml siguiendo las

etiquetas del SDK de Android.

• En cualquier sitio podemos referenciar a variables del fichero strings.xml.

Esto es muy útil para aplicaciones en varios idiomas.

Como hacer aplicaciones compatibles con todas las versiones

Seguramente mas de uno se ha encontrado con el problema de no poder usar funcionalidades del API 2.2 si quiere que su aplicacion siga siendo compatible con los moviles que aun tiene Android 1.5

Pensando el otro día se me ocurrió este método, espero que os sirva y lo encontreis útil:

La máquina virtual tiene la particularidad de que mientras no se acceda a una clase con llamadas a funciones de un API superior no salta la excepcion de validacion, por lo tanto se trata de no permitir que cargue en ningun momento esas clases.

Para ilustrarlo mejor pongo un ejemplo.

Page 61: Base de Datos en Android

Queremos llamar a un método solo disponible en el API 2.0 como pueda ser:

Código :

... overridePendingTransition(enterAnim, exitAnim); ...

Si un movil con, por ejemplo, una version de Android 1.5 se encuentra algo así en una de nuestras Activity no dejara cargarla y nos sacara del programa con una excepcion de validacion porque los bytecodes de ese método no los reconoce.

Para evitar esto montamos las siguientes clases:

Código :

public class Compatibility { public static int version() { if (Build.VERSION.SDK.equals("1.5")) return 3; return Api5.version(); }

public static void Activity_overridePendingTransition(Activity me, int enterAnim, int exitAnim) { if (version()<5) return; Api5.Activity_overridePendingTransition(me, enterAnim, exitAnim); }

}

public class Api5 { public static int version() { return Build.VERSION.SDK_INT; }

public static void Activity_overridePendingTransition(Activity me, int enterAnim, int exitAnim) { me.overridePendingTransition(enterAnim, exitAnim); }}

Y nuestra llamada al método problemático quedaría de la siguiente forma:

Código :

... Compatibility.Activity_overridePendingTransition(this, enterAnim, exitAnim); ...

Con esto logramos que en caso de detectarse un API que no soporte ese método (version()<5) no hacemos nada, mientras que si sí se está ejecutando en un API valido llamamos a la clase API5 donde alojaremos todo el código problemático y que nunca se cargará en móviles con API menor a la version 2.0 ya que la clase Compatibility filtra todas las llamadas.