Escolar Documentos
Profissional Documentos
Cultura Documentos
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.
Código :
import android.database.sqlite.SQLiteDatabase;
SQLiteDatabase db;
Código :
db = ctx.openOrCreateDatabase("bdprueba", 0, null);
Código :
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);
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.
Código :
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.
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 :
-----------------------------------------------------------------
Código :
.....package.....
import android.database.sqlite.SQLiteDatabase;
.....otros imports que se necesiten.....
SQLiteDatabase db;
String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS tablita (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"dato text NOT NULL);";
}catch(Exception e){
Log.d("BASEDEDATOS", "Exception initDB: " + e.toString());
}
}
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;
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.
Saludos.
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 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.
Aquí os dejo un sencillo tutorial para aprender a lanzar notificaciones en la barra de estado.
<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;
//Lanzamos la notificación
mNotificationManager.notify(0, notification);
//Cerramos la aplicación
finish();
}
}
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:
<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:
<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;
TextView selection;
"purus"};
@Override
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;
TextView selection;
"purus"};
@Override
super.onCreate(icicle);
setContentView(R.layout.main);
setListAdapter(new IconicAdapter(this));
selection=(TextView)findViewById(R.id.seleccion);
selection.setText(items[position]);
Activity context;
IconicAdapter(Activity context) {
this.context=context;
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);
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.
* 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.
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:
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:
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.
//*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/
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:
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
this.context = context;
}
if (fila == null) {
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;
}
return (label);
}
}
}
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.
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.
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.
Código :
public class ProgressDialogExample extends Activity implements Runnable {
@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) {
handler.sendEmptyMessage(0);
}
}
};
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:
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.
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.
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 :
Modificaciones:
Código :
startActivityForResult(intent, IDENTIFICADOR);
Código :
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 :
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.
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 :
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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 :
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;
Código XML:
Código android:
package android.prueba;
import android.app.Activity;
import android.os.Bundle;
Código XML:
</LinearLayout>
Código AndroidManifest.XML
Código XML:
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
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);
Código :
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.
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.
http://code.google.com/android/reference/android/content/Intent.html
Saludos.
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.
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.
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 fundamental del método es saber que tecla se ha pulsado, para ello usaremos lo
siguiente:
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.
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.
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.
En el siguiente capitulo veremos como dibujar marcas de sitios en el mapa, así como
conseguir mostrar información sobre los mismos.
2º Paso.
3º Paso.
4º Paso.
5º Paso.
6º Paso.
7º Paso.
Gracias a Apache.
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
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 */
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.
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) {
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
5
6 return mDb.insert(DATABASE_TABLE, null, initialValues);
7 }
El método borrar es muy obvio asi que pasamos a recuperar una nota de la
base de datos:
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 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
02
xmlns:android="http://schemas.android.com/apk/res/android"
03 android:layout_width="wrap_content"
04 android:layout_height="wrap_content">
05
06 <ListView android:id="@android:id/list"
07 android:layout_width="wrap_content"
08 android:layout_height="wrap_content"/>
09 <TextView android:id="@android:id/empty"
10 android:layout_width="wrap_content"
11 android:layout_height="wrap_content"
12 android:text="@string/no_notes"/>
13
14 </LinearLayout>
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.
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:
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 =
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}
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 }
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
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 <string name="menu_delete">Delete Note</string>
2 <string name="title">Title</string>
3 <string name="body">Body</string>
4 <string name="confirm">Confirm</string>
5 <string name="edit_note">Edit Note</string>
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:
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:
7 fillData();
8 registerForContextMenu(getListView());
9}
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 =
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
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 }
15 android:layout_width="wrap_content"
16 android:layout_height="wrap_content"
17 android:layout_weight="1"/>
18 </LinearLayout>
19
20 <TextView android:layout_width="wrap_content"
21 android:layout_height="wrap_content"
22 android:text="@string/body" />
<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" />
27
28 <Button android:id="@+id/confirm"
29 android:text="@string/confirm"
30 android:layout_width="wrap_content"
31 android:layout_height="wrap_content" />
32
33 </LinearLayout>
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.
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);
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
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 }
mTitleText.setText(title);
Resumen
• 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!
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
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
01 // AndroidManifest.xml
02 <?xml version="1.0" encoding="utf-8"?>
<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">
<application android:icon="@drawable/icon"
07
android:label="@string/app_name">
08 <activity android:name=".HolaMundo"
09 android:label="@string/app_name">
10 <intent-filter>
<action android:name="android.intent.action.MAIN"
11
/>
<category
12
android:name="android.intent.category.LAUNCHER" />
13 </intent-filter>
14 </activity>
15 </application>
16 </manifest>
03
04 import android.app.Activity;
05 import android.os.Bundle;
06
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 <?xml version="1.0" encoding="utf-8"?>
<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 >
08 <TextView
09 android:layout_width="fill_parent"
10 android:layout_height="wrap_content"
11 android:text="@string/hello"
12 />
13 </LinearLayout>
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.
Hemos visto paso por paso lo que hace Android para ejecutar un sencillo Hola
Mundo. Lo importante es:
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.
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.
Código :
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.