Você está na página 1de 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.
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
- 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){
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.
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:
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:
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"

>
<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",


"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;
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);

}
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().
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
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);
}
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));
}

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() {


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"?>
<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"
>
<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;
}
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);


}
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---


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);
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
}
}

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 {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Load the preferences from an XML resource


addPreferencesFromResource(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.
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:
[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>
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" />
<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:


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,
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
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.
3º Paso.
4º Paso.
5º Paso.
6º Paso.
7º Paso.
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.
Conexión a la base de datos
Una 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

public void onUpgrade(SQLiteDatabase


16
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 /**
* Abre la base de datos de notas. Si no puede abrirla, la crea.
25
Si no se puede
26 * lanza una excepcion
27 */
28 public NotasDbAdapter open() throws SQLException {...}
29
30 public void close() {...}
31
32 /**
* Inserta una nueva nota con el t’tulo y el texto dados. Si se
33
crea correctamente
* devuelve el rowId, en caso contrario, devuelve -1 para
34
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
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
public void onUpgrade(SQLiteDatabase
13
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

private static final String DATABASE_CREATE = "create table notes (_id


1 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);
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);

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
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 notas
Vamos a modificar el layout de la actividad inicial /res/layout/notepad_list.xml
01 &lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout
02
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.xml
1 &lt;?xml version="1.0" encoding="utf-8"?&gt;
2 &lt;TextView android:id="@+id/text1"
xmlns:android="http://schemas.android.com/apk/res
3
/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 {
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 }
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() {


// Recuperamos todas las notas de la DB y creamos una lista
02
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) {
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.
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.java


1 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.xml
1 &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
02 public boolean onContextItemSelected(MenuItem item) {
03 switch(item.getItemId()) {
04 case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo)
05
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);
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 cursor
03 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

protected void onListItemClick(ListView l, View


02
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 }
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) {
String editTitle =
16
extras.getString(NotasDbAdapter.KEY_TITLE);
String editBody =
17
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.
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
&lt;LinearLayout
03
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
04
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;
&lt;EditText android:id="@+id/body"
23
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;
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 actividad
25 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);


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) {
String title =
36
extras.getString(NotasDbAdapter.KEY_TITLE);
37 String body = extras.getString(NotasDbAdapter.KEY_BODY);
38 mRowId = extras.getLong(NotasDbAdapter.KEY_ROWID);

39
// Insertamos los valores actuales de la nota en los
40
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


bundle.putString(NotasDbAdapter.KEY_TITLE,
56
mTitleText.getText().toString());
bundle.putString(NotasDbAdapter.KEY_BODY,
57
mBodyText.getText().toString());
58 if (mRowId != null) {
bundle.putLong(NotasDbAdapter.KEY_ROWID,
59
mRowId);
60 }

61
// y los mandamos de vuelta al método que los está
62
esperando
63 Intent mIntent = new Intent();
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:


• 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
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:
• 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í
• /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.
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;
&lt;manifest
03
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;
&lt;application android:icon="@drawable/icon"
07
android:label="@string/app_name"&gt;
08 &lt;activity android:name=".HolaMundo"
09 android:label="@string/app_name"&gt;
10 &lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN"
11
/&gt;
&lt;category
12
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;
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;
&lt;LinearLayout
03
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;
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.


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.

Você também pode gostar