Beruflich Dokumente
Kultur Dokumente
HOLA MUNDO
2014/09/04/ B Y ALEJANDRO ALCALDE , 9 COMMENTS ,
IN ANDROID, OPENSOURCE
CREANDO EL PROYECTO
Arrancamos eclipse con todo configurado correctamente y vamos a Archivo->nuevo>Proyecto Android:
Nombre de la aplicacin (El que se mostrar al usuario una vez instalada, Hola
Mundo).
Marcamos la opcin Crear Actividad para que eclipse cree la clase que se lanzar al
ejecutar la aplicacin. Normalmente a esta clase se le llamaMainActivity.
Versin Mnima del SDK es la versin mnima necesaria del SDK para ejecutar la
aplicacin, a menor nmero, la aplicacin correr en ms terminales, pero no podremos
usar las ltimas caracteristicas de Android.
Ya hemos creado nuestro primer proyecto Android, ahora vamos a ver de qu se compone:
compilador y se genera el fichero de recursos R, que nos permite acceder a ellos de una
forma rpida.
Est dividida en subcarpetas:
drawable: Ficheros bitmap(.png, .9.png, .jpg, .gif) o XML con contenidos que se
dibujarn (fondos, botones etc).
Algunas carpetas pueden tener varias versiones para adaptarse a diferentes tamaos de
pantallas, idiomas etc.
PROFUNDIZANDO EN EL HOLA
MUNDO
package app.tutorial.holaMundo;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Al crear el proyecto dimos nombre a una Actividad (MainActivity), estas clases son las
encargadas de mostrar las interfaz grfica al usuario, deben extender de la clase Activity.
Al crear una activity Android llama a su mtodo onCreate() que hace lo necesario para
mostrar la pantalla al usuario. Tal y como est la actividad al crear el proyecto. Hace una
llamada a setContentView(), que tiene como parmetro el identificador de una vista ya
creada.
Por lo tanto, R.layout.main referencia a un archivo xml situado en la carpeta ./res/layout
(ficheros de definicin de pantalla).
ARCHIVO ./RES/LAYOUT/MAIN.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"
/>
</linearlayout>
En este archivo se define una pantalla en la que los elementos se agruparn de forma lineal
(LinearLayout) y con un componente de texto (TextView). Al componente de texto le
fijamos el texto a mostrar con la referencia @string/hello(valor del item en
./res/values/strings.xml)
ARCHIVO ./RES/VALUES/STRINGS.XML
< ?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MainActivity!</string>
<string name="app_name">Hola Mundo</string>
</resources>
En este archivo se definen el paquete por defecto, datos de versin, icono (mediante una
referencia). El nombre de la aplicacin (otra referencia al fichero strings.xml). Despues se
define el comportamiento de la aplicacin. Se aaden dos filtros para que la actividad que
definimos anteriormente sea usada como principal (android.intent.action.MAIN) y para
que sea incluida en el men de aplicaciones (android.intent.category.LAUNCHER)
FUNDAMENTOS
PROGRAMACIN ANDROID:
CONCEPTOS BSICOS Y
COMPONENTES
2014/09/04/ B Y ALEJANDRO ALCALDE , 3 COMMENTS ,
IN ANDROID, OPENSOURCE
CONCEPTOS BSICOS
Hemos visto que un proyecto Android est formado por varias carpetas estructuradas, pero
lo que se instala en los dispositivos es un fichero con extensin .apk (application package).
Estos ficheros se generan con la herramienta apk (En el directorio tools del SDK) al
terminar de compilar.
Las aplicaciones en Android tienen su propio entorno seguro de ejecucin:
Cada proceso se ejecuta en su propia mquina virtual, de esta manera est aislada
del resto. De esta forma ante cualquier fallo en la aplicacin solo afecta a su mquina
virtual, no al resto.
COMPONENTES DE LAS
APLICACIONES
La caracterstica principal de Android es la reutilizacin de componentes de una aplicacin
por otra.
Por ejemplo, imaginemos que estamos desarrollando una aplicacin que almacena datos de
libros junto con una fotografa de su portada. En lugar de tener que escribir el cdigo para
capturar o seleccionar la imagen de la portada, podemos pasar el control a la aplicacin de
la cmara del telfono, o a la galera, as una vez tomemos una foto o seleccionemos una
imagen de la galera se nos devuelve el control a nuestra aplicacin con la imagen
seleccionada.
Para poder realizar estas operaciones, estamos obligados a dividir nuestras aplicaciones en
mdulos independientes que solo realicen una tarea concreta.
Veamos ahora otro ejemplo, muchos terminales tienen la opcin de compartir algo en las
redes sociales, por ejemplo Twitter, un mdulo claramente definido de esta aplicacin es
por ejemplo la opcin de enviar un mensaje o tweet, si seguimos la filosofa de dividir
nuestras aplicaciones en mdulos, la funcin de enviar un mensaje sera una actividad
independiente que recibe como parmetro el mensaje a enviar, si no recibe parmetro se
mostrar el formulario para escribirlo. Dicha actividad usar la API de Twitter para enviar
el mensaje y finalmente cerrar la actividad devolviendo el control a la aplicacin que la
llam. De esta forma, y con los filtros adecuados en el AndroidManifest.xml, cada
aplicacin que quiera compartir algo en twitter llamar a esta actividad pasandole como
parmetro el mensaje.
Con esto llegamos a la conclusin de que las aplicaciones Android no tienen un punto de
entrada y otro de salida, podemos definir todos los que necesitemos.
Para realizar todas estas operaciones, Android proporciona cuatro tipos decomponentes
bsicos:
ACTIVIDADES (ACTIVITY)
Son las encargadas de mostrar la interfaz de usuario e interactuar con l. Responden a los
eventos generados por el usuario (pulsar botones etc). Heredan de la clase Activity
El aspecto de la actividad se aplica pasando un objeto View(Encargado de dibujar una parte
rectangular en la pantalla, pueden contener ms objetos View, adems todos los
componentes de la interfaz (botones, imagenes etc) heredan de View) al
mtodo Activity.setContentView(), que es el mtodo encargado de dibujar la pantalla.
Normalmente las vistas ocupan toda la pantalla, pero se pueden configurar para que se
muestren como flotantes. Las actividades tambin pueden llamar a componentes que se
mostrarn sobre su View (como dialogos o mens).
Por cada pantalla distinta hay una actividad distinta, normalmente las aplicaciones tienen
una actividad fijada como punto de entrada. Por ejemplo:
Una aplicacin que lee el correo tendr las siguientes actividades:
SERVICIOS
No tienen interfaz visual y se ejecutan en segundo plano, se encargan de realizar tareas que
deben continuar ejecutandose cuando nuestra aplicacin no est en primer plano. Todos los
servicios extienden de la clase Service
Continuando con el ejemplo anterior, la aplicacin de correo tendr un servicio que
comprobar y descargar nuevos correos. Es posible lanzar o conectar con un servicio en
ejecucin con la interfaz que proporciona la clase Service.
Los servicios disponen de un mecanismo para ejecutar tareas pesadas sin bloquear la
aplicacin ya que se ejecutan en un hilo distinto.
PROVEEDORES DE CONTENIDO
(CONTENTPROVIDER)
Ponen un grupo de datos a disposicin de distintas aplicaciones, extienden de la
clase ContentProvider para implementar los mtodos de la interfaz, pero para acceder a
esta interfaz se ha de usar una clase llamada ContentResolver
Con esta clase se permite acceder al sistema de ficheros, bases de datos SQLite o cualquier
otra fuente de datos unificada.
Un lector de correo podra disponer de un ContentProvider para acceder a la bandeja de
entrada y los datos del mensaje.
FUNDAMENTOS
PROGRAMACIN ANDROID:
INTENTS Y
ANDROIDMANIFEST
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
INTENTS
Las Actividades, Servicios y BroadcastReceiver se activan a travs de mensajes asncronos
llamados intent
Un intent es un objeto que contiene todos los datos del mensaje.
Hay tres mtodos para activar cada uno de los componentes:
ANDROIDMANIFEST
Para poder usar un componente, adems de crearlo extendiendo de su clase
correspondiente, es necesario definirlo en el AndroidManifest.xml. Este archivo podemos
editarlo directamente como XML, o con el formulario que nos facilita eclipse.
Cada componente tiene su propia etiqueta xml:
: Para actividades.
: Para servicios.
: Para categorizar componentes, as cuando se les llame no hay que saber el nombre
del intent, android lo elige basandose en su categora y parmetros.
FUNDAMENTOS
PROGRAMACIN ANDROID:
ACTIVIDADES, TAREAS,
PROCESOS E HILOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
ACTIVIDADES Y TAREAS
Las actividades conforme se van ejecutando van apilandose en una pila. Cuando
finalizamos una actividad, con el mtodo finish() o con la tecla atrs del telfono, la
actividad se extrae de la pila, quedando encima de la pila la actividad que se abri
anteriormente.
Si ejecutamos una actividad varias veces sin cerrarla, sta aparecer en la pila tantas veces
como la hayamos ejecutado. La pila de actividades se enva al segundo plano cuando la
aplicacin pierde el foco, y vuelve al primer plano cuando la aplicacin vuelve a tomar el
control.
Podemos modificar este comportamiento con flags que pasamos al objeto Intent a partir de
las propiedades de la activity descritas en el AndroidManifest
Si una pila de tareas se abandona por el usuario durante un periodo de tiempo y el sistema
necesita ms recursos, se limpia la pila de actividades (excepto la actividad principal), este
comportamiento se puede modificar en el manifiesto:
Atributo
Funcin
alwaysRetainTaskStat
e
clearTaskOnLaunch
finishOnTaskLaunch
PROCESOS E HILOS
Como cada aplicacin se ejecuta en un proceso Linux distinto, todos los componentes y
procesos de dicha aplicacin corren en el mismo hilo. Esto se puede modificar con el
atributo process de cada componente (activity, provider, receiver y service). En la
etiqueta application del manifest podemos poner este atributo para que sea aplicado a todos
sus elementos.
Para gestionar tareas pesadas podemos usar hilos para ejecutar dichas tareas en un hilo
aparte (ejecutarlas en segundo plano). Para llevar a cabo esta operacin usaremos el
objeto Thread de java, aunque Android proporciona otros objetos para facilitar el trabajo,
como Handler, AsyncTask o Looper. (entre otros).
FUNDAMENTOS
PROGRAMACIN ANDROID:
CICLO DE VIDA DE LOS
COMPONENTES
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 1 COMMENT ,
IN ANDROID, OPENSOURCE
Cada componente tiene un ciclo de vida distinto. Las superclases de estos componentes
tienen mtodos callbackque les permiten reaccionar ante un cambio de estado. Cada
mtodo callback est obligado a llamar al mismo mtodo de su padre.
mtodo, Android considera que el receiver est inactivo, pero el hilo sigue ejecutndose y
puede ser eliminado de la pila, interrumpiendo la tarea.
Se soluciona lanzando un servicio desde este mtodo que se encarga de hacer las tareas
pesadas, as, al tener el servicio su propio ciclo de vida, seguir ejecutandose, aunque el
receiver se considere inactivo.
Pausado: La actividad sigue siendo visible para el usuario, pero ha perdido el foco.
Por ejemplo que se haya mostrado un cuadro de dialogo delante de nuestra actividad.
Debemos guardar el estado de la interfaz y los datos de esta actividad antes de entrar en
este estado, ya que podramos perderlos si el sistema necesita ms recursos de memoria.
La clase Activity dispone de mtodos que se llaman cada vez que sta cambia de estado,
para permitirnos realiar tareas como guardar los datos antes de cambiar de estado, y cargar
la actividad ms rpido la proxima vez que se muestre. A continuacin un diagrama con los
distintos estados por los que pasa una actividad:
onPause(): Es llamado justo antes de que se traiga a primer plano otra actividad.
Aqu es donde debemos guardar los datos para no perder la informacin de la actividad
si esta es sacada de la pila. Dentro de este mtodo tambin se suele parar las tareas
pesadas que consuman CPU.
Un ejemplo de uso de estos mtodos puede ser cuando tenemos una aplicacin que carga
datos de internet, deberamos cargar los datos al inicio de la actividad, una vez descargados,
guardaramos el estado de la actividad para que si es destruida, no sea necesario volver a
descargar los datos.
Para realizar esta operacin usaramos el mtodo onSavedInstanceState(), que creara
un Bundle con los datos necesarios que pasaramos al mtodo onCreate()la segunda vez
que cargaramos la actividad, sin necesidad de volver a descargar los datos.
FUNDAMENTOS
PROGRAMACIN ANDROID:
LIMPIEZA DE PROCESOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Android va destruyendo componentes inactivos para liberar memria, pero los elminia
teniendo en cuenta cual es el de menor importancia:
Los primeros en ser elmininados son los procesos vacos (Son aplicaciones cerradas
que se mantienen en memoria para cargar rpidamente la aplicacin la proxima vez que
se abra.)
Procesos en segundo plano, estos son las aplicaciones que ya han ejecutado su
mtodo onStop(), Android confecciona una lista con los procesos en este estado y
elimina en primer lugar el ms antiguo.
Es muy importante implementar bien los mtodos de estado, para evitar perden
informacin.
PROGRAMACIN ANDROID:
TRABAJAR CON
ACTIVIDADES Y PASAR
PARMETROS ENTRE ELLAS
2014/ 09/ 05/ B Y ALEJANDRO ALCALDE , 41 COMMENTS ,
IN ANDROID, OPENSOURCE
Voy a explicar un poco por encima que hace cada fichero del proyecto:
./RES/LAYOUT/MAIN.XML
En este layout principal vamos a aadir dos botones que nos servirn para lanzar las nuevas
actividades que creemos despus.
./RES/LAYOUT/SEGUNDA_ACTIVIDAD.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:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/cadena1" />
<textview android:id="@+id/params"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<button android:id="@+id/boton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/cadena1" />
</linearlayout>
Este layout vamos a usarlo para mostrar los parmetros que pasemos de una actividad a otra
./SRC/MAINACTIVITY.JAVA
package com.elbauldelprogramador.actividades;
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;
import android.widget.Toast;
public class mainActivity extends Activity {
protected static final int REQUEST_CODE = 10;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Capturamos los objetos grficos que vamos a usar
Button button1 = (Button) findViewById(R.id.button1);
Button button2 = (Button) findViewById(R.id.button2);
// Fijamos un evento onclick para el button1, cada vez que
// lo pulsemos se llamar a este mtodo (que abrir una actividad)
button1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(mainActivity.this, Activity1.class);
startActivity(intent);
}
});
//button2 pasar parmetros a otra actividad, y los devolver
button2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(mainActivity.this, ParametrosActivity.class);
// damos valor al parmetro a pasar
intent.putExtra("param1", "valor del parmetro 1 (viene de mainActivity)");
/*
* Inicia una actividad que devolver un resultado cuando
* haya terminado. Cuando la actividad termina, se llama al mtodo
* onActivityResult() con el requestCode dado.
* El uso de un requestCode negativo es lo mismo que llamar a
* startActivity(intent) (la actividad no se iniciar como una
* sub-actividad).
*/
startActivityForResult(intent, REQUEST_CODE);
}
});
}
/*
* ste mtodo se llama cuando la actividad que iniciamos con un startActivityForResult
* finaliza, dandi el REQUEST_CODE con el que llam, el resultCode se devuelve, junto con
* algunos datos adicionales, el resultCode ser RESULT_CANCELED si la actividad devuelve
* eso explcitamente, si no devuelve ningn resultado o si la operacin finaliz de forma
inesperada.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
// cogemos el valor devuelto por la otra actividad
String result = data.getStringExtra("result");
// enseamos al usuario el resultado
Toast.makeText(this, "ParametrosActivity devolvi: " + result, Toast.LENGTH_LONG).show();
}
}
}
./SRC/ACTIVITY1.JAVA
package com.elbauldelprogramador.actividades;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class Activity1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.segunda_actividad);
// Capturamos los objetos grficos que vamos a usar
TextView text = (TextView) findViewById(R.id.textView1);
Button button = (Button) findViewById(R.id.boton);
// Agregamos al textView un texto
text.setText(R.string.cadena1);
// Cambiamos el texto al botn
button.setText(R.string.salir);
// Evento onclick del botn, cuando se pulse, cerramos la actividad
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
}
./SRC/PARAMETROSACTIVITY.JAVA
package com.elbauldelprogramador.actividades;
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;
import android.widget.TextView;
public class ParametrosActivity extends Activity {
private static final int OK_RESULT_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.segunda_actividad);
// Capturamos los objetos grficos que vamos a usar
TextView text = (TextView) findViewById(R.id.textView1);
Button button = (Button) findViewById(R.id.boton);
TextView params = (TextView) findViewById(R.id.params);
text.setText(R.string.cadena2);
button.setText(R.string.salir);
//Al pulsar el botn cerramos la ventana y volveremos a la anterior
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//Cierra la actividad y la saca de la pila
returnParams();
}
});
// Mostramos los parmetros recibidos de la actividad mainActivity
Bundle reicieveParams = getIntent().getExtras();
params.setText(reicieveParams.getString("param1"));
}
protected void returnParams() {
Intent intent = new Intent();
intent.putExtra("result", "'Valor devuelto por ParametrosActivity'");
setResult(OK_RESULT_CODE, intent);
finish();
}
}
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
CONCEPTOS BSICOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Un nmero
La constante FILL_PARENT, que indica que la vista debe intentar ser tan grande
como su padre, quitando el padding.
AT_MOST, el padre fija un tamao mnimo para el hijo. El hijo(y los descendientes
de ste) tienen que ocupar por lo menos ese tamao.
Un atributo imprescindible es el id(de tipo entero). Que sirve para identificar nicamente a
un objeto View. Cuando lo declaramos mediante xml podemos referenciarlo a travs de la
clase de recursos R, usando una @.
Los objetos View pueden tener otros muchos atributos, como padding, colores, imgenes,
fondos, mrgentes etc
CONTEXT
Si ya has programado algo en Android, o has visto alguno de los ejemplos, probablemente
hayas visto que muchos mtodos referidos a la vista piden como parmetro un objeto de
tipo context.
Context es una interfaz para la informacin global de la aplicacin. A travs de l podemos
acceder a recursos, clases y operaciones, como lanzar actividades, manejar intents etc.
Podemos acceder al contexto de diferentes formas en funcin de donde nos encontremos:
Las actividades implementan esta interfaz, por lo que haciendo referencia a ellas
mismas, con (this) o NombreActivity.this, estaremos referenciando el contexto.
Usando otros mtodos como getApplicationContext() o getApplication()
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
LAYOUTS
2014/09/04/ B Y ALEJANDRO ALCALDE , 3 COMMENTS ,
IN ANDROID, OPENSOURCE
Los layout nos permiten posicionar cada objeto grfico en el lugar que queramos de la
pantalla, es decir, nos permite disear el aspecto grfico que va a tener nuestra pantalla. Los
layouts son de tipo ViewGroup, una subclase de View
Existen varios tipos de Layouts para Android, vamos a ver los ms comunes:
FRAMELAYOUT
Este tipo de Layout es el ms bsico, coloca a sus objetos hijos en la parte superior
izquierda de la pantalla.
< ?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
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"/>
<textview android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"/>
</framelayout>
LINEARLAYOUT
Este tipo de layout coloca sus hijos unos detras de otros, tambin comenzando por la
esquina superior izquierda de la pantalla. Podemos colocarlos alineados horizontalmente o
verticalmente mediante su propiedadandroid:orientation=horizontal | vertical
< ?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<textview android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:background="#0ff"/>
<textview android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:background="#ff0"/>
</linearlayout>
RELATIVELAYOUT
Este Layout permite que coloquemos los elementos en un lugar con respecto a la posicin
de otro, es decir, colocar un botn a la derecha de un texto, o centrarlo en la pantalla, o por
ejemplo, colocar un texto encima de tal elemento y a la derecha de este otro.
Para conseguir esto, RelativeLayout proporciona propiedades
comoandroid:layout_toRightOf o android:layout_alignLeft, que toman como valores los
identificadores de los objetos, o valores booleanos.
< ?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<textview android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:background="#0ff"
android:layout_centerInParent="true"
android:id="@+id/text1"/>
<textview android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:background="#ff0"
android:layout_below="@id/text1"/>
</relativelayout>
Para saber ms acerca de todos los tipos de layouts que hay podis
visitarhttp://developer.android.com/guide/topics/ui/layout-objects.html
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
COMPONENTES GRFICOS Y
EVENTOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 7 COMMENTS ,
IN ANDROID, OPENSOURCE
Ya hemos visto que todos los componentes visuales descienden del objeto View, que
proporciona una interfaz para que podemos interactuar con ellos.
Para que nuestras aplicaciones sean funcionales, necesitamos responder a los eventos que el
usuario dispare al interactuar con nuestro programa, en Android, esto se consigue mediante
los Listeners, que sern llamados cada vez que se produzca un evento.
Por ejemplo, un listener muy comn ser setOnClickListener(), que responder cada vez
que se pulse sobre la vista a la que se lo aplicamos, como un botn, o una imgen. Hay
muchos tipos de listener, setOnKeyListener() (Para eventos de
teclado), setOnItemClicklistener() (Para eventos al seleccionar un elemento de una lista)
etc etc.
En los ejemplos mostrados hasta ahora, solo hemos visto objetos de tipo TexView, vamos a
ver unos cuantos ms (En cada ejemplo pondr la definicin XML del objeto, y su
manipulacin mediante cdigo):
BUTTON
Botones simples, para realizar acciones al pulsar sobre ellos.
<button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Plsame"
android:layout_centerInParent="true"
android:id="@+id/button1"/>
//Recoger el botn en una variable para usarlo
final Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(
button1.getContext()
, "Me has pulsado " + ++contador + " veces."
, Toast.LENGTH_SHORT)
.show();
}
});
En este caso, hemos declarado una variable como miembro de la clase, (public int
contador = 0;), para que cada vez que pulsemos el botn nos salga un mensaje con el
nmero de veces que lo hemos pulsado:
EDITTEXT
Son campos de texto en los que el usuario puede escribir.
<edittext android:layout_width="200dip"
android:layout_height="wrap_content"
android:layout_above="@id/button1"
android:id="@+id/editText1"
android:layout_centerInParent="true"/>
final EditText editText1 = (EditText) findViewById(R.id.editText1);
editText1.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
if (arg1 == KeyEvent.KEYCODE_ENTER){
Toast.makeText(
editText1.getContext()
, "Escribiste: " + editText1.getText()
, Toast.LENGTH_SHORT)
.show();
return true;
}
return false;
}
});
Lo que hemos hecho con este EditText, es fijarle un onKeyListener, que comprobar (con el
if), que hemos pulsado la tecla enter, y si es cierto, mostrar el texto escrito:
IMAGEVIEW
Nos permite mostrar imgenes en la pantalla.
<imageview android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
final ImageView imageView1 = (ImageView) findViewById(R.id.imageView);
imageView1.setImageResource(R.drawable.icon);
CHECKBOX
Es un tipo de botn con dos estados, activo o inactivo, practicamente tiene el mismo
comportamiento de un botn, una de sus caractersticas es que podemos comprobar si el
botn esta activo o no:
<checkbox android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="CheckBox"
android:layout_centerInParent="true"
android:layout_below="@id/button1"
android:id="@+id/checkBox1" />
final CheckBox checkbox1 = (CheckBox) findViewById(R.id.checkBox1);
checkbox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton arg0, boolean checked) {
if (checked) Toast.makeText(checkbox1.getContext(), "Activo", Toast.LENGTH_LONG).show();
else Toast.makeText(checkbox1.getContext(), "Inactivo", Toast.LENGTH_SHORT).show();
}
});
En este caso, hemos usado como listener onCheckedChanged, que se ejecutar cada vez
que el estado del checkbox cambie.
Download EjemploComponentesGraficosejemploComponentesGraficos.zip
Downloaded 1124 times
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
ADAPTERS I
2 0 1 4 / 0 9 / 0 4 / B Y A L E J A N D R O AL C A L D E , 11 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Un objeto Adaptador acta como puente entre un AdapterView y los datos de una Vista
(View). El adaptador permite el acceso a los elementos de datos, ste tambin es
responsable de crear una vista para cada elemento en la coleccin de datos.
Se puede decir, que los adaptadores son colecciones de datos, que asignamos a una vista
para que sta los muestre, por ejemplo, podemos crear un ArrayAdapter a partir de un array
de string ya creado y con datos, y asignar este adaptador a un ListView, as, el ListView
mostrar los datos del array.
Como vemos, al crear el arrayAdapter, tenemos que pasar tres parmetros, el contexto, un
layout que se usar para dibujar cada item (en este casosimple_list_item_1, que ya viene
definido por android), ms adelante veremos como crear los nuestros propios, y como
tercer parmetro la coleccin de datos.
Aprovechando que en la anterior entrada hablamos de los eventos, voy a explicar como
fijar un evento onclick para cada elemento de la lista.
//Evento que se disparar al pulsar en un elemento de la lista
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView< ?> arg0, View arg1, int arg2,
long arg3) {
ListAdapter la = (ListAdapter) arg0.getAdapter();
Toast.makeText(
arg1.getContext()
,la.getItem(arg2).toString()
,Toast.LENGTH_LONG)
.show();
};
});
Para realizar este tipo de cosas, android proporciona una clase llamada ListActivity, este
tipo de clase necesita que exista una vista con el id ya definido por
Android@android:id/list y otra con el id @android:id/empty (Tal y como lo definimos en
nuestro layout), as, si el adaptador que le asiganamos a la lista no tiene datos, se mostrar
al usuario la vista empty, el cdigo quedara de la siguiente manera:
package app.elbauldelprogramador.adapters;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class AdaptadoresActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Array que asociaremos al adaptador
String[] array = new String[] {
"Elemento 1"
,"Elemento 2"
,"Elemento 3"
,"Elemento 4"
,"Elemento 5"
,"Elemento 6"
};
//Creacin del adaptador, vamos a escoger el layout
//simple_list_item_1, que los mostr
ListAdapter adaptador = new ArrayAdapter<string>(
this, android.R.layout.simple_list_item_1, array);
//Asociamos el adaptador a la vista.
ListView lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adaptador);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Toast.makeText(
AdaptadoresActivity.this
,l.getItemAtPosition(position).toString()
,Toast.LENGTH_LONG)
.show();
}
}
</string>
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
ADAPTERS II
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 26 COMMENTS ,
IN ANDROID, OPENSOURCE
Para explicar el funcionamiento nos vamos a basar en un ejemplo que listar las distintas
versiones de Ubuntu.
Lo primero que debemos hacer es crearnos una clase que almacenar los datos de cada una
de las versiones:
package app.elbauldelprogramador.adapters2;
public class VersionesUbuntu {
private String nombre;
private String version;
A continuacin vamos a crear el adaptador desde cero, siendo necesario extender de la clase
BaseAdapter.
package app.elbauldelprogramador.adapters2;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class VersionesUbuntuAdapter extends BaseAdapter{
private ArrayList<versionesubuntu> listadoVersiones;
private LayoutInflater lInflater;
}
}
</versionesubuntu>
Lo que hace esta clase es lo siguente, en su constructor, carga un objeto LayoutInflater, que
infla los objetos XML del layout para que podamos usarlos, convirtindolos en un objeto
java.
Tambin tenemos tres mtodos sencillos (getCount, getItem, getItemId), que se encargan
de devolver el nmero de elementos de la coleccin, un elemento en concreto y el
identificador de un elemento.
El mtodo getView() se invoca cada vez que hay que dibujar la lista.
En este caso, para la lista, hemos usado un layout personalizado, que es el siguiente:
< ?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<imageview android:id="@+id/logo"
android:src="@drawable/ocelot"
android:layout_alignParentLeft="true"
android:padding="5px"
android:layout_width="128px"
android:layout_height="128px"/>
<textview android:id="@+id/nomVersion"
android:layout_toRightOf="@id/logo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="15dip"
android:text="VersionNom" />
<textview android:id="@+id/numVersion"
android:layout_below="@id/nomVersion"
android:layout_toRightOf="@id/logo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="VersionNum" />
</relativelayout>
Por ltimo, tan solo queda usar el adaptador que hemos creado en los pasos anteriores en
nuesta Actividad principal, en este caso, una ListActivity:
package app.elbauldelprogramador.adapters2;
import java.util.ArrayList;
import android.app.ListActivity;
import android.os.Bundle;
public class Adaptadores2Activity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList<versionesubuntu> versiones =
new ArrayList</versionesubuntu><versionesubuntu>();
versiones.add(
new VersionesUbuntu("Lucid Lynx", "10.4 LTS", R.drawable.lucid));
versiones.add(
new VersionesUbuntu("Maverick Meerkat", "10.10", R.drawable.u1010));
versiones.add(
new VersionesUbuntu("Natty Narwhal", "11.04", R.drawable.natty));
versiones.add(
new VersionesUbuntu("Oneiric Ocelot", "11.10", R.drawable.ocelot));
VersionesUbuntuAdapter adaptador = new VersionesUbuntuAdapter(
Adaptadores2Activity.this, versiones);
setListAdapter(adaptador);
}
}
</versionesubuntu>
PROGRAMACIN ANDROID:
INTERFAZ GRFICA MENS
2014/09/04/ B Y ALEJANDRO ALCALDE , 4 COMMENTS ,
IN ANDROID, OPENSOURCE
Los mens en las aplicaciones son algo que encontramos frecuentemente, de hecho, casi
todos los terminales Android tienen un botn especfico para desplegarlos.
Se dispone de distintos tipo de mens:
Options Menu: El men tpico, que se despliega al pulsar la tecla men, que se
divide en dos grupos:
Icon menu:Muestra un men con iconos, 6 elementos como mximo.
Expanded Menu: Se usa cuando hay ms de 6 elementos, mostrando un elemento
con la palabra Ms.
Context Menu: Mens contextuales desplegados al realizar una pulsacin larga en una
View.
Submens: Mens desplegados al pulsar sobre un elemento de otro men.
OPTIONS MENU
Lo ms simple y sencillo es definir los mens en XML, colocado en ./res/menu, para este
ejemplo he definido el siguiente menu, que contiene dos elementos, un About y un Quit:
< ?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/about"
android:icon="@drawable/about"
android:title="About App">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/submenu"
android:title="Submen de &quot;About App&quot;"/>
</menu>
</item>
<item android:id="@+id/quit"
android:title="Quit App"
android:icon="@drawable/quit"/>
</menu>
Bien, voy a explicar un poco la estructura de este men, Empezamos declarando el men
con la etiqueta
, que contendr todos sus elementos bajo la etiqueta , en este caso, tambin tenemos
un submenu, que se declara igual que el men principal.
Los atributos de cada elemento son su identificador, el icono a mostrar y el ttulo.
Para poder usar este men, necesitamos inflarlo (Convertir el fichero XML en un objeto
java), para hacer esto, hay que llamar a MenuInflater.inflate(), el cdigo siguiente infla el
fichero xml anterior en el mtodo callbackonCreateOptionsMenu().
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ejemplo_menu, menu);
return true;
}
Ahora, tenemos que responder a las acciones del usuario cuando pulse algn elemento de
nuestro men, para ello vamos a sobreescribir el mtodoonOptionsItemSelected()
@Override
CONTEXT MENU
Los mens contextuales son similares a los mens mostrados al hacer click con el botn
derecho de un ratn en un PC, para crearlos, debemos sobreescribir el
mtodo onCreateContextMenu(), donde inflaremos el archivo xml.
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ejemplo_menu, menu);
}
Al igual que en los options menu, tenemos que responder a las acciones del usuario:
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.about:
Toast.makeText(
MenusActivity.this
,"Ejemplo Mens App"
,Toast.LENGTH_LONG)
.show();
return true;
case R.id.quit:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Pero este men contextual no se va a mostrar, ya que tenemos que asociarlo para que se
lanze al realizar una pulsacin prolongada sobre una view, en este caso un botn:
final Button boton = (Button) findViewById(R.id.button1);
registerForContextMenu(boton);
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
DILOGOS Y
NOTIFICACIONES
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 21 COMMENTS ,
IN ANDROID, OPENSOURCE
En ocasiones hay que mostrar mensajes al usuario para informarle del estado de la
aplicacin, o del estado de las operaciones que se estn llevando a cabo.
Android dispone de tres tipos de notificaciones:
Notificaciones Toast.
Ventanas de dilogo.
NOTIFICACIONES TOAST
Una notificacin Toast es un mensaje que se muestra superpuesto en la pantalla. Solo ocupa
el espacio necesario para mostrar la alerta, mientras tanto, la actividad que estaba visible
puede seguir usndose. Este tipo de notificaciones se muestran durante un periodo de
tiempo y desaparecen, no permiten interactuar con ellas. Debido a que un Toast se crea
mediante un servicio en segundo plano, puede aparecer aunque la aplicacin no est visible.
A lo largo de todas las entradas sobre Android, se ha usado mucho este tpo de
notificaciones:
Toast.makeText(context, text, duration).show();
</linearlayout>
El resultado es el siguiente:
Al igual que los Toast, se puede crear un layout personalizado, para ms informacin
visite:http://developer.android.com/guide/topics/ui/notifiers/notifications.html
DILOGOS
Por ltimo, vamos a ver los dilogos, que son ventanas que se muestran delante de las
actividades, y pueden recibir acciones del usuario, hay varios tipos:
AlertDialog
ProgressDialog
DatePickerDialog
TimePickerDialog
Los dos ltimos parmetros son para que el dilogo sea indeterminado, y para que se pueda
cerrar con la flecha de atrs del terminal.
PROGRAMACIN ANDROID:
INTERFAZ GRFICA
ESTILOS Y TEMAS
2014/09/04/ B Y ALEJANDRO ALCALDE , 2 COMMENTS ,
IN ANDROID, OPENSOURCE
Un estilo es una coleccin de propiedades que especifican que aspecto ha de tener un objeto
View o una ventana. Con los estilos podemos definir propiedades como la altura, relleno,
color del texto, fondo etc. Los estilos en Android comparten la filosofa de las hojas de
estlo en cascada (CSS), permitiendo separar el diseo del contenido.
Como podemos comprobar con este ejemplo, el cdigo queda mucho ms lmpio usando
estilos:
Sin estilos:
<textview android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#00FF00"
android:typeface="monospace"
android:text="@string/hello" />
Con estilos:
<textview style="@style/CodeFont"
android:text="@string/hello" />
DEFINIENDO ESTILOS
Los estilos se definen en un fichero de recursos distinto al layout, colocado en el
directorio /res/values. stos ficheros no tienen porqu tener un nombre en concreto, pero
por convencin se suelen llamar styles.xml themes.xml
El nodo raiz de estos archvos debe ser .
Para cada estilo que queramos definir, hay que aadir un elemento
y un atributo name para ese estlo (es obligatorio), despus, aadiremos un elemento para
cada propiedad del estilo, que debe tener obligatoriamente el atributo name que declara la
propiedad del estilo y su valor. Los valores parapueden ser una palabra clave, valor
hexadecimal, una referencia a un recurso u otro valor dependiendo de la propiedad del
estilo. Veamos un ejemplo:
<style name="CodeFont" parent="@android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#00FF00</item>
<item name="android:typeface">monospace</item>
</style>
HERENCIA
Como acabamos de ver, el atributo parent sirve para heredar propiedades de otros estilos,
podemos heredar tanto de estilos del sistema como de los nuestros propios:
Del sistema:
<style name="GreenText" parent="@android:style/TextAppearance">
<item name="android:textColor">#00FF00</item>
</style>
En este caso, no usamos el atributo parent, ya que estamos usando un estilo propio, tambin
se puede apreciar que podemos heredar cuantas veces queramos, como es el caso de
(CodeFont.Red.Big)
</activity>
A continuacin, dejo una captura del ejemplo que he hecho para esta entrada, que se puede
descargar desde:
Para saber ms acerca de los estilos y temas visite la pgina oficial: Applying Styles and
Themes
PROGRAMACIN ANDROID:
RECURSOS INTRODUCCIN
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Ya hemos visto que Android separa los recursos (imgenes, sonidos etc) del cdigo
colocndolos organizados dentro del directorio ./res. Esto nos facilita su mantenimiento,
adems de permitirnos usar diferentes recursos dependiendo de la configuracin del
terminal.
Separar los recursos permite proporcionar alternativas para dar soporte a las distintas
configuraciones de dispositivos, como idiomas o tamaos de pantalla. Para conseguir
compatibilidad con las diferentes configuraciones, debemos organizar los recursos en el
directorio ./res de nuestros proyectos, dentro de subdirectorios para agruparlos por tipo y
configuracin.
Un recurso puede usarse por defecto (Se mostrar en cualquier dispositivo,
independientemente de su configuracin), o pueden especificarse recurosos alternativos
(Que se mostrn en los dispositivos para configuraciones determinadas), vemoslo con unas
imgenes de ejemplo:
Dos dispositivos distintos, usando recursos por defecto:
Por ejemplo, podemos crear iconos ms pequeos para que sean mostrados en los
terminales con pantallas ms pequeas o disear una disposicin de pantalla diferente para
cuando la aplicacin se est ejecutando en modo apaisado, para conseguir esto,
simplemente creamos una carpeta de recursos aadiendo el sufijo que indica la situacin en
la que debe usarse.
Para el caso del idioma, crearamos un archivo xml con las cadenas traducidas a dicho
idioma, en este caso ingls, y lo colocaramos dentro de ./res/values-en/strings.xml.
Para el caso del layout personalizado cuando la pantalla est en modo apaisado, meteramos
nuestro layout dentro de res/layout-land/
.
Para saber ms acerca de los tipos de sufijos que se pueden usar, visita Providing Resources
en la pgina oficial de Android.
PROGRAMACIN ANDROID:
RECURSOS USANDO
RECURSOS
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 1 COMMENT ,
IN ANDROID, OPENSOURCE
A todos los recursos que colocamos en las subcarpetas de ./res/ se puede acceder a travs de
la clase R de nuestro proyecto.
Esta clase R la genera el comando aapt en una pasada anterior a la compilacin
(Eclipse, por defecto, la va generando continuamente conforme cambiamos los
recursos). Contiene todos los identificadores de recursos para poder referenciarlos.
Al igual que la carpeta res, la clase R se organiza en subclases, as por ejemplo el icono
que colocamos en ./res/drawable/icon tiene su correspondencia en
R.drawable.icon (que es un identificador esttico de tipo int y sirve para acceder
al recurso).
Subclase de recurso, cada grupo tiene la suya (drawable, string, style, layout).
Nombre del recurso que, segn el tipo, ser: el nombre del fichero sin la extensin o el
atributo xml android:name si es un valor sencillo (cadena, estilo, etc.).
Tenemos dos formas de acceder a los recursos definidos en la clase R:
En el cdigo, accediendo a las propiedades de la clase R directamente
(R.string.nombre).
En los ficheros XML, usando una notacin especial: @grupo_recursos/
nombre_recurso, es decir, el recurso anterior se accedera con @string/nombre.
Si lo que queremos es acceder a un recurso definido por el sistema antepondremos el
prefijo android:
./res/values/style.xml
< ?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MiTema" parent=
"@android:style/Theme.Light">
<item name="android:windowBackground">
@drawable/fondo</item>
<item name="cabecera">
@style/TituloRojo</item>
</style>
<style name="TituloRojo"
parent="@android:style/TextAppearance.Large">
<item name="android:textColor">#FF0000</item>
<item name="android:textStyle">bold</item>
</style>
</resources></p>
PROGRAMACIN ANDROID:
RECURSOS STRINGS
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 1 COMMENT ,
IN ANDROID, OPENSOURCE
Como ya hemos visto, los recursos juegan un papel muy importante en la arquitectura
Android. Un recurso en Android es un archivo (como un fichero de msica) o un valor
(como el ttulo de un Dilogo) que est ligado a una aplicacin ejecutable. Estos archivos
estn ligados a un ejecutable de tal manera que podemos cambiarlos sin necesidad de
recompilar la aplicacin.
Los ejemplos de recursos ms familiares son cadenas de texto, colores e imgenes. En lugar
de escribir las cadenas de texto en el cdigo fuente, usamos sus IDs. Esta indireccin nos
permite cambiar el valor de la cadena sin tener que cambiar el cdigo fuente.
Existen mucho recursos en Android, que vamos a ver a lo largo de las etradas posteriores.
Empezaremos por un recurso muy comn, los string:
RECURSOS STRING
Android permite definir strings en uno o ms archivos XML de recursos. Estos archivos
estn bajo el directorio ./res/values. El nombre del archivo XML para este tipo de recurso
puede ser cualquiera, pero por convencin se suele llamarstrings.xml. Veamos un ejemplo
de este fichero:
< ?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello</string>
<string name="app_name">Hello app_name</string>
</resources>
Cuando este archivo se crea o modifica, el plugin ADT de eclipse automticamente crear o
actualizar una clase java de nuestra aplicacin llamada R.java alojada en el directorio
./gen, que contiene los IDs nicos para las dos cadenas que acabamos de crear.
Para el fichero strings.xml que acabamos de crear, tendremos lo siguiente en la clase R:
package nombre.de.nuestro.paquete;
public final class R {
//.. otras entradas dependiendo de tu proyecto y aplicacin
public static final class string {
//.. otras entradas dependiendo de tu proyecto y aplicacin
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
//.. otras entradas dependiendo de tu proyecto y aplicacin
}
//.. otras entradas dependiendo de tu proyecto y aplicacin
}
Como vemos como primero R.java define una clase principal en el paquete raiz:public
final class R. Depues, define una clase interna llamada public static final class string.
R.java crea esta clase esttica interna como espacio de nombres para guardar los IDs de los
recursos string.
La definicin de los dos public static final int llamados app_name y hello son los IDs de
los recursos que representan nuestras cadenas de texto. Podemos usar estos IDs en
cualquier lugar de nuestro cdigo mediante R.string.hello o R.string.app_name
La estructura del fichero string.xml es muy fcil de seguir. Tenemos un elemento raiz
llamado , seguido por uno o ms elementos hijos . Cada elemento tiene una propiedad
llamada name que ser la que usar como identificador R.java.
Para comprobar que se permiten varios recursos de string en el directorio values, vamos a
crear otro fichero llamado strings1.xml con lo siguiente:
< ?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello1">Hello</string>
<string name="app_name1">Hello app_name</string>
</resources>
Ahora, el plugin ADT de eclipse se encargar de actualizar el fichero R.java, que contendr
lo siguiente:
package nombre.de.nuestro.paquete;
public final class R {
//.. otras entradas dependiendo de tu proyecto y aplicacin
public static final class string {
//.. otras entradas dependiendo de tu proyecto y aplicacin
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
public static final int app_name1=0x7f040006;
public static final int hello1=0x7f040005;
//.. otras entradas dependiendo de tu proyecto y aplicacin
}
//.. otras entradas dependiendo de tu proyecto y aplicacin
PROGRAMACIN ANDROID:
RECURSOS LAYOUT
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
En Android, cada pantalla de una aplicacin habitualmente se carga desde un fichero XML
que actua de recurso. Un recurso layout es un recurso clave que se usa en Android para
componer la UI de nuestra aplicacin. Vamos a considerar el segmenteo de cdigo siguiente
como ejemplo de una actividaden Android.
Vamos a ver la composicin de este fichero, como elemento raiz tenemos un elemento
llamado , que contiene un TextView seguido de un Button. Un LinearLayout coloca a sus
hijos uno detrs de otro vertical u horizontalmente.
Para cada pantalla que queramos hacer, necesitaremos ficheros layout distintos, mejor
dicho, cada layout debe estar en un fichero, como ./res/layout/screen1.xml y
./res/layout/screen2.xml
Por cada archivo de layout que tengamos en ./res/layout, se generar una entrada en R.java.
Por ejemplo, si tenemos estos dos archivos, file1.xml y file2.xml, en R.java aparecer:
// ...
public static final class layout {
public static final int file1=0x7f030000;
public static final int file2=0x7f030001;
}
// ..
Las vistas definidas en estos layout, como el TextView son accesibles mediante cdigo java
a travs sus IDs de recursos generadas en R.java.
TextView tv = (TextView) this.findViewById(R.id.text1);
tv.setText("Texto para el TextView")
El valor del atributo id, indica que la constante llamada text1 ser usada para identificar
nicamente a esa vista. El signo + de +id/text1 significa que el ID text1 ser creado si no
existe. En la siguiente entrada se tratar la sintaxis de los recursos.
PROGRAMACIN ANDROID:
RECURSOS SINTAXIS DE
LOS RECURSOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Independientemente del tipo de recurso (de string y layout son los dos que hemos visto
hasta ahora), Todos los recursos Android estn identificados (o referenciados) por sus ids en
cdigo fuente Java.
La sintaxis que usamos para crear un ID de recurso en un fichero XML se llama resourcereference syntax (sintaxis de referencia a recurso). La sintaxis del atributo id que vimos
anteriormente (@+id/text1) tiene la siguiente estructura formal:
@[package:]type/name
R.drawable
R.id
R.layout
R.string
R.attr
R.plural
R.array
drawable
id
layout
string
attr
plurals
string-array
<textview android:id=text>
<!-- Error de compilacin, como id no tomar cadenas de texto sin formato. -->
</textview><textview android:id=@text>
<!-- Sintaxis incorrecta. No disponde de tipo y nombre-->
<!-- debera ser @id/text, @+id/text o @string/string1-->
<!-- obtendremos el siguiente error: No resource type specified-->
</textview><textview android:id=@id/text>
<!-- Error: No hay ningn recurso que coincida con el id text-->
<!-- a no ser que lo hayamos definido nosotros mismos con anterioridad.-->
</textview><textview android:id=@android:id/text>
<!-- Error: el recurso no es pblico-->
<!-- lo que indica que no hay tal identificacin en android.R.id-->
<!-- Por supuesto esto ser vlido si el archivo android R.java defini un id con este nombre.-->
</textview><textview android:id=@+id/text>
<!-- Correcto: crea un id llamado text en el paquete R.java local.-->
</textview>
PROGRAMACIN ANDROID:
RECURSOS COMPILADOS Y
NO COMPILADOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Android soporta principalmente dos tipos de recursos: archivos XML y archivos raw (como
imgenes, audio y vdeo). Incluso dentro de los archivos XML, has podido ver que en
algunos casos los recursos estn definidos como valores dentro del archivo XML (las
cadenas de texto, por ejemplo). En otras ocasiones, un archivo XML es un recurso por s
mismo, como los Layout.
Podemos encontrar dos tipos de archivos XML: uno se compilar a un formato binario y el
otro se copiar tal como es al dispositivo. Como ejemplo podemos poner los ficheros XML
de recursos string y los ficheros de layout, ambos se compilarn a un formato binario antes
de formar parte del paquete de instalacin. Estos ficheros XML tienen formatos
predefinidos en los que los nodos XML se traducen a IDs.
Por supuesto, tambin se pueden elegir archivos XML para guardarlos con su formato
propio, estos archivos no sern interpretados y se les asignar un ID de recurso para poder
identificarlos. Sin embargo, podemos querer que estos ficheros tambin se compilen a un
formato binario. Para lograrlo, hay que colocarlos bajo el directorio ./res/xml. En tal caso,
deberemos usar los lectores XMl que proporciona Android para acceder a los nodos del
fichero.
Si colocamos cualquier tipo de archivo, incluyendo ficheros XML, bajo ./res/raw, no se
compilarn a un formato binario. Deberemos entonces, para leerlos, usar Stream. Los
archivos de audio y vdeo entran en esta categora tambin.
Hay que destacar, que al formar parte el directorio rar de ./res/*, incluso estos archivos raw
de audio y vdeo sern localizados como todos los dems recursos.
Como vimos, los recursos se almacenan en varios subdirectorios segn su tipo, a
continuacin vemos algunos de los subdirectorios ms importantes de la carpeta res.:
drawable: Bitmaps
El compilador de recursos AAPT (Android Asset Packaging Tool), compila todos los
recursos excepto los raw y lo coloca en el fichero .apk (Android package) final. Este
fichero es el que contiene el cdigo de las aplicaciones Android y los recursos, similar a
los .jar de Java. Estos ficheros son los que usamos para instalar aplicaciones en Android.
PROGRAMACIN ANDROID:
RECURSOS ARRAYS DE
STRINGS
2014/09/04/ B Y ALEJANDRO ALCALDE , 9 COMMENTS ,
IN ANDROID, OPENSOURCE
Se pueden definir arrays de strings como recursos en cualquier archivo bajo el subdirectorio
./res/values. Para definirlos, usaremos un nodo XML llamado string-array. Este nodo es un
hijo de resources, al igual que el nodo string. A continuacin, vamos a ver como crear un
array de strings:
<resources>
<string -array name="test_array">
<item>uno</item>
<item>dos</item>
<item>tres</item>
</string>
</resources>
Una vez definido el recurso, podemos usarlo en el cdigo Java de la siguiente manera:
//Accedemos al objeto 'Recursos' desde la Activity
Resources res = nombre-de-la-actividad.getResources();
PROGRAMACIN ANDROID:
RECURSOS PLURALES
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
Los recursos Plurals son un conjunto de strings. Estos strings representan una forma de
escribir cantidades numricas, por ejemplo, cuantos huevos hay en una cesta. Vamos a ver
un ejemplo:
Hay 1 huevo
Hay 2 huevos
Hay 10 huevos
Como puedes notar, las frases son iguales para los nmeros 2 y 10. Sin embargo, la frase
para 1 huevo es diferente. Android permite representar esta variacin con el recurso
llamado plurals. En el siguiente ejemplo vemos como se representan estas dos variaciones.
<resources>
<plurals name="huevos_en_una_cesta">
<item quantity="one">Hay 1 huevo</item>
<item quantity="other">Hay %d huevos</item>
</plurals>
</resources>
Las dos variaciones se representan como dos cadenas de texto diferentes bajo el mismo
plural. Ahora, podemos usarlo desde el cdigo Java para mostrar correctamente la cadena
correspondiente a la cantidad de huevos. El primer parmetro de getQuantityString() es el
ID del plural. El segundo selecciona la cadena a usar. Cuando el valor de la cantidad es 1,
usamos la cadena tal como es. Cuando el valor es distinto a 1, debemos pasar un tercer
parmetro que ser el valor a colocar en el lugar de %d. Siempre deber haber al menos 3
parmetros si usamos cadenas formateadas en los plurales.
Resources res = tu_actividad.getResources();
String s1 = res.getQuantityString(R.plurals.huevos_en_una_cesta, 0, 0);
String s2 = res.getQuantityString(R.plurals.huevos_en_una_cesta, 1, 1);
String s3 = res.getQuantityString(R.plurals.huevos_en_una_cesta, 2, 2);
String s4 = res.getQuantityString(R.plurals.huevos_en_una_cesta, 10, 10);
Con este cdigo, cada cantidad se mostrar con su correcta cadena de texto.
Existen otras posibilidades que podemos aplicar al atributo quantity del elemento item. Para
ello, recomiendo que lean el cdigo fuente de Resources.java y PluralsRules.java para
entenderlo correctamente. An as, dejo lo fundamental de estas dos ficheros para que
entiendan bien el funcionamiento:
PLURALRULES.JAVA
abstract class PluralRules {
static final int QUANTITY_OTHER = 0x0000;
static final int QUANTITY_ZERO = 0x0001;
static final int QUANTITY_ONE = 0x0002;
static final int QUANTITY_TWO = 0x0004;
static final int QUANTITY_FEW = 0x0008;
static final int QUANTITY_MANY = 0x0010;
static final int ID_OTHER = 0x01000004;
abstract int quantityForNumber(int n);
final int attrForNumber(int n) {
return PluralRules.attrForQuantity(quantityForNumber(n));
}
static final int attrForQuantity(int quantity) {
// see include/utils/ResourceTypes.h
switch (quantity) {
case QUANTITY_ZERO: return 0x01000005;
case QUANTITY_ONE: return 0x01000006;
case QUANTITY_TWO: return 0x01000007;
case QUANTITY_FEW: return 0x01000008;
case QUANTITY_MANY: return 0x01000009;
default:
return ID_OTHER;
}
}
static final String stringForQuantity(int quantity) {
switch (quantity) {
case QUANTITY_ZERO:
return "zero";
case QUANTITY_ONE:
return "one";
case QUANTITY_TWO:
return "two";
case QUANTITY_FEW:
return "few";
case QUANTITY_MANY:
return "many";
default:
return "other";
}
}
static final PluralRules ruleForLocale(Locale locale) {
String lang = locale.getLanguage();
if ("cs".equals(lang)) {
if (cs == null) cs = new cs();
return cs;
}
else {
if (en == null) en = new en();
return en;
}
}
private static PluralRules cs;
private static class cs extends PluralRules {
int quantityForNumber(int n) {
if (n == 1) {
return QUANTITY_ONE;
}
else if (n >= 2 && n < = 4) {
return QUANTITY_FEW;
}
else {
return QUANTITY_OTHER;
}
}
}
private static PluralRules en;
private static class en extends PluralRules {
int quantityForNumber(int n) {
if (n == 1) {
return QUANTITY_ONE;
}
else {
return QUANTITY_OTHER;
}
}
}
}
RESOURCES.JAVA
public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
PluralRules rule = getPluralRule();
CharSequence res = mAssets.getResourceBagText(id, rule.attrForNumber(quantity));
if (res != null) {
return res;
}
res = mAssets.getResourceBagText(id, PluralRules.ID_OTHER);
if (res != null) {
return res;
}
throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
+ " quantity=" + quantity
+ " item=" + PluralRules.stringForQuantity(rule.quantityForNumber(quantity)));
}
private PluralRules getPluralRule() {
synchronized (mSync) {
if (mPluralRule == null) {
mPluralRule = PluralRules.ruleForLocale(mConfiguration.locale);
}
return mPluralRule;
}
}
En la mayoria de los idiomas normalmente hay dos posibles valores, one y other, pero
para el Checo, los valores son one para 1, few del 2 al 4 y other para el resto.
PROGRAMACIN ANDROID:
RECURSOS TRABAJAR
CON RECURSOS XML
ARBITRARIOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 6 COMMENTS ,
IN ANDROID, OPENSOURCE
Adems de los recursos estructurados que hemos ido viendo, Android permite usar archivos
XML arbitrarios como recursos. Esto proporciona una forma rpida de referenciar los
archivos basandose en su Id de recurso as como permitirnos localizar estos archivos de una
manera sencilla. Como ltima ventaja, nos permite compilar y almacenar estos archivos en
el dispositivo eficientemente.
Los ficheros XML que se lean de esta manera, tiene que almacenarse bajo el directorio
./res/xml. A continuacin vamos a ver un ejemplo:
<rootelem1>
<subelem1>
Hello World from an xml sub element
</subelem1>
</rootelem1>
Como hace con cualquier otro fichero XML de recursos, el AAPT compila este fichero
antes de colocarlo en el paquete de la aplicacin. Ahora necesitamos usar una instancia
de XmlPullParser para poder parsear el archivo. Para obtener la instancia
de XmlPullParser usando el siguiente cdigo desde cualquier contexto (incluyendo una
activity):
Resources res = activity.getResources();
XmlResourceParser xpp = res.getXml(R.xml.test);
}//eof-function
PROGRAMACIN ANDROID:
RECURSOS TRABAJAR
CON RECURSOS RAW
2014/09/04/ B Y ALEJANDRO ALCALDE , 2 COMMENTS ,
IN ANDROID, OPENSOURCE
Los recursos Raw se colocan bajo el directorio ./res/raw. Son recursos raw archivos como
ficheros de audio, vdeo o archivos de texto que requieran localizacin o ser referenciados
mediante IDs de recursos.
A diferencia de los archivos XML, colocados en ./res/xml, estos archivos no se compilan,
se mueven al paquete de la aplicacin tal y como son. Sin embargo, a cada fichero se le
asignar un identificador en la clase R.java. Si colocamos un archivo de texto
en ./res/raw/test.txt, podremos leerlo usando el cdigo de abajo:
}
private String convertStreamToString(InputStream is)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = is.read();
while (i != -1)
{
baos.write(i);
i = is.read();
}
return baos.toString();
}
Los nombres de ficheros con el mismo nombre base generan un error en el plugin ADT de
eclipse.
PROGRAMACIN ANDROID:
RECURSOS TRABAJAR
CON RECURSOS ASSETS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
PROGRAMACIN ANDROID:
RECURSOS REPASANDO LA
ESTRUCTURA DEL
DIRECTORIO DE RECURSOS
2014/09/04/ B Y ALEJANDRO ALCALDE , 0 COMMENTS ,
IN ANDROID, OPENSOURCE
/colors.xml
/dimens.xml
/attrs.xml
/styles.xml
/drawable/*.png
/*.jpg
/*.gif
/*.9.png
/anim/*.xml
/layout/*.xml
/raw/*.*
/xml/*.xml
/assets/*.*/*.*
PROGRAMACIN ANDROID:
RECURSOS RECURSOS Y
CAMBIOS DE
CONFIGURACIN
2014/ 09/ 04/ B Y ALEJANDRO ALCALDE , 1 COMMENT ,
IN ANDROID, OPENSOURCE
Los recursos ayudan a la localizacin. Por ejemplo, podemos tener valores para
strings que cambien en funcin del idioma configurado en el terminal. Los recursos
Android generalizan esta idea para cualquier configuracin del dispositivo, el
idioma es tan solo otra configuracin ms. Otro ejemplo de cambios de
configuracin se d cuando el dispositivo cambia de posicin (de vertical a
horizontal o viceversa). El modo vertical se suela llamar portrait y el horizontal
landscape.
Android permite elegir distintas configuraciones de layout basandose en el tipo de
layout. Y ambos tendrn el mismo ID de recurso. Esto se consigue usando
directorios diferentes para cada configuracin. Vamos a verlo con un ejemplo:
/res/layout/main_layout.xml
/res/layout-port/main_layout.xml
/res/layout-land/main_layout.xml
Aunque hay tres archivos layout separados, solo se generar un nico ID para ellos
en R.java. Este ID ser de la forma R.layout.main_layout
Sin embargo, cuando recuperemos el layout correspondiente a este ID,
obtendremos el layout apropiado para la configuracin actual del dispositivo.
En el ejemplo anterior, las extensiones de los directorios -port y -land se
llamanconfiguration qualifiers. Estos clasificadores (qualifiers), se tienen que
separar del directorio original aadiendo un guin (-) a su nombre. Los recursos
para los que especificamos estos clasificadores de configuracin se llaman recursos
alternativos. Los recursos almacenados en el directorio de recursos sin los
clasificadores de configuracin se llaman recursos por defecto.
En la siguiente lista se muestran los clasificadores de configuracin disponibles:
/res/layout-ldpi
/res/layout-hdpi
/res/layout-car
Para saber nuestra localizacin actual podemos ejecutar una aplicacin que viene
instalada en el emulador android. La encontramos en el men de aplicaciones y se
llama Custom Locale.
/res/layout-port/main_layout.xml
/res/layout-en/main_layout.xml
// values-en-rUS/string_en_us.xml
<resources xmlns="http://schemas.android.com/apk/res/android">
<string name="teststring_all">test-en-us</string>
</resources>
// values-port/string_port.xml
<resources xmlns="http://schemas.android.com/apk/res/android">
<string name="teststring_all">test-en-us-port</string>
<string name="testport_port">testport-port</string>
<string name="t1_enport">t1_port</string>
<string name="t1_1_en_port">t1_1_port</string>
</resources>
// values/string_en_port.xml
<resources xmlns="http://schemas.android.com/apk/res/android">
<string name="teststring_all">test-en-port</string>
<string name="t1_1_en_port">t1_1_en_port</string>
</resources>
Como se aprecia, aunque hemos definido muchos strings, solo se han generado
cinco IDs. A continuacin se describe el comportamiento para cada string, que se
ha probado con en_US y el modo portrait:
t1_enport: Este Id est en tres variaciones, default, -en y -port. Debido a que
se encuentra en -en y -port al mismo tiempo, se escoger el valor de -en
t2: Este ID se encuentra solo en default, por lo tanto se elige el valor de ah.
El SDK de Android tiene algoritmos ms detallados an, sin embargo, con este
ejemplo se ha mostrado lo esencial. La clave est en darse cuenta de la precedencia
de cada variacin sobre otra. A continuacin, para aquellos que deseen ampliar
informacin dejo unas URLs de referencia:
REFERENCIAS
SEGUNDA PARTE:
PROGRAMACIN ANDROID:
STRICTMODE
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 3 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Android 2.3 introdujo una funcionalidad de depuracin llamada StrictMode. Segn Google,
usaron esta caracterstica para hacer cientos de mejoras a sus aplicaciones Android. Lo que
hace el StrictMode es informar de las violaciones de polticas relacionadas con los hilos y la
mquina virtual. Si se detecta dicha violacin, obtenemos una alerta que nos lo indica.
Junto a la alerta tendremos tambin una traza de la pila de ejecucin (Stack Trace), donde
podremos comprobar el lugar en el que se produjo la violacin. En ese momento, podemos
forzar el cierre de la aplicacin o simplemente escribirla en el log y dejar que la aplicacin
continue su ejecucin.
Actualemente hay dos tipos de polticas disponibles para usar con StrictMode. La primera
de ellas es referente a los hilos y est destinada principalmente a ejecutarse en el hilo
principal, tambin conocido como el hilo de UI (User Interface).
No es una buena prctica hacer lecturas/escrituras a disco desde el hilo principal, como
tampoco lo es realizar accesos a red. Google ha aadido al cdigo del disco y de
red hooks o ganchos, que son algoritmos abstractos que invocan a mtodos abstractos. Por
lo tanto, si activamos StrictMode para uno de nuestros hilos, y ese hilo realiza cualquiera de
las dos acciones mencionadas anteriormente, seremos informados. Podemos elegir sobre
qu aspectos de la poltica de hilos queremos ser informados, as como el mtodo por el
cual se nos informar. Normalmente las que usaremos sern accesos a disco y red. En
cuanto al mtodo por el que seremos informados, pordemos elegir: Escribirlo en el LogCat,
mostrar un dilogo, hacer un destello en la pantalla, escribir en el archivo log de DropBox o
forzar el cierre de la aplicacin. Normalmente se usa el LogCat o forzar el cierre. A
continuacin vemos un ejemplo de como configurar StrictMode para polticas de hilos:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
Podemos ver que la calse Builder hace que configurar StrictMode sea bastante fcil. Todos
los mtos que definen las polticas devuelven una referencia al objeto Builder. El
ltimo, build(), devuelve un objeto ThreadPolicy, que es el argumento
quesetThreadPolicy() espera recibir. setThreadPolicy() es un mtodo esttico, por ello no es
necesario instanciar un objeto de tipo StrictMode. En el ejemplo anterior, se ha configurado
la poltica para que avise de lecturas-escrituras a disco, acceso a red y vamos a ser
informados a travs del logCat. Podemos usar detectAll() para ahorrarnos escribir los otros
mtodos de deteccin. Tambin podemos usar el mtodo penaltyDeath() para forzar el
cierre de la aplicacin una vez escrita la alerta StrictMode al LogCat.
Debido a que con el cdigo de arriba hemos activado el StrictMode, no necesitamos seguir
activndolo. Por lo tanto, podemos habilitar StrictMode al principio del
mtodo onCreate() de nuestra actividad principal, ya que se ejecuta en el hilo principal,
avisndonos de todo lo que pase en ese hilo.
StrictMode tambin dispone de VmPolicy, que comprueba prdidas de memoria si un
objeto SQLite finaliza antes de que haya sido cerrado, o si cualquier objeto que pueda ser
cerrado ha finalizado antes de ser cerrado. Las VmPolicy se crean de una forma similar
como se muestra a continuacin. Sin embargo, hay una diferencia entre stas y
ThreadPolicy, que no pueden usar alertas a travs de dilogos.
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
Ya que la configuracin ocurre en un hilo, quizs nos sorprenda que el cdigo se est
ejecutando en el hilo principal, pero la traza de la pila (Stack Trace) est ah para ayudarnos
a averiguar en qu punto se produjo la violacin. Una vez detectada la violacin, podemos
resolverla moviendo el cdigo que la produce a un hilo en segundo plano propio. O por otra
parte podemos decidir que el cdigo est bien en esa parte y no moverlo.
Algo importante que debemos hacer a la hora de distribuir nuestra aplicacin es apagar el
StrictMode. Hay varias formas de conseguir esto. La ms sencilla es eliminar las llamadas a
los mtodos, pero hacer esto dificulta seguir desarrollando la aplicacin. Podemos declarar
un booleano al nivel de la aplicacin y comprobar su valor antes de llamar a StrictMode.
De este modo, al enviar la aplicacin a produccin, simplemente daramos a esta variable el
valor false y de se llamar nunca a StrictMode.
Un mtodo ms elegante para resolver este problema, es usar el atributodebuggable en
nuestro AndroidManifest. Este atributo se coloca en el tag de la forma android:debuggable.
Una vez activado este atributo, puede fijarse como verdadero o falso dependiendo de si
queremos depurar la aplicacin o no. Podemos comprobar el estado de este atributo como
se muestra ms abajo. De modo que cuando est activado, tendremos StrictMode activo, y
cuando no lo est, no.
//Devuelve si la aplicacin est en modo debug o no
ApplicationInfo appInfo = context.getApplicationInfo();
int appFlags = appInfo.flags;
if ((appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0){
//Aqu configuraramos el StrictMode
}
try{
Class strictMode = Class.forName("android.os.StrictMode");
Method enableDefaults = strictMode.getMethod("enableDefaults");
enableDefaults.invoke(null);
}catch(Exception e){
//Este dipositivo no soporta StrictMode
Log.v("StrictMode", "no soportado, ignorando...");
}
Como se puede apreciar, simplemente hemos metido todos los ejemplos que vimos
anteriormente en una clase. Ahora para configurar StrictMode tenemos que hacer lo
siguiete:
try{
StrictModeWrapper.init(this);
}catch(Throwable throwable){
Log.v("StrictMode", "no soportado, ignorando...");
}
this es el contexto local del objeto desde el que llamemos al mtodo init, por ejemplo
podra ser desde el mtodo onCreate() de nuestra actividad principal.
EJEMPLO DE USO
MEDIANTE EL PENALTYLOG():
MEDIANTE PENALTYDIALOG():
PROGRAMACIN ANDROID:
PROVEEDORES DE
CONTENIDO
INTRODUCCIN
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
content://com.android.note.NoteProvider/notes
Para recuperar una nota especfica de la base de datos de notas, (la nota 25 por ejemplo), se
necistar una URI como la siguiente:
content://com.android.note.NoteProvider/notes/25
En futuras entradas veremos como estas Uris se traducen para usarse con los mecanismos
de acceso a la base de datos. Cualquier aplicacin del dispositivo puede usar estas URIs
para acceder y manipular datos. Como consecuencia, los CV desempean un papel
importante compartiendo datos entre aplicaciones.
Estrictamente hablando, la responsabilidad de los CV abarcan ms mecanismos de
encapsulacin que el acceso a datos. Se necesitar un mecanismo de acceso a datos como
por ejemplo SQLite o acceso a red para recibir datos.Debido a esto, La abstraccin de los
CV se requiere solamente si queremos compartir datos externamente o entre aplicaciones.
Para el acceso interno a los datos, nuestra aplicacin puede usar cualquier mecanismo de
almacenamiento/acceso de datos de entre los siguientes:
SQLite: Bases de datos SQLite, Cada una es privada al paquete que la crea.
Red: Un mecanismo que permite recibir o almacenar datos externamente a travs de
internet.
PROGRAMACIN ANDROID:
ARQUITECTURA DE LOS
PROVEEDORES DE
CONTENIDOS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 4 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Sitios webs
REST
Servicios web
Procedimientos Almacenados
Un authoroty es como un nombre de dominio para ese CV. Con el authority anterior, las
urls de nuestro proveedor comenzarn con ese prefijo:
content://com.elbauldelprogramador.provider.FavSites
Como se ve, los CV, como los sitios web, tienen un nombre de dominio base que acta
como URL inicial.
Los CV tambin proporcionan URLs del tipo REST para recuperar o manipular datos. Para
el registro que acabamos de ver, el URI para identificar un directorio o una coleccin de
datos en la base de datos de FavSites ser:
content://com.elbauldelprogramador.provider.FavSites/sites
content://media/external/images
content://contacts/people
content://contacts/people/23
PROGRAMACIN ANDROID:
PROVEEDORES DE
CONTENIDOS LEER DATOS
MEDIANTE URIS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 1 C O M M E N T ,
IN ANDROID, OPENSOURCE
Ya que las URIs definidas por un Proveedor de contenidos (CV) son nicas para ese
proveedor, es muy importante que estas URIs estn bien documentadas. Los proveedores
que Android proporciona hacen esto definiendo constantes que representan las cadenas de
la URI.
Consideremos estas tres URIs definidas en el SDK de Android:
MediaStore.Images.Media.INTERNAL_CONTENT_URI
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
Contacts.People.CONTENT_URI
content://media/external/images
content://contacts/people
El proveedor MediaStore define dos URIs y Contacts uno. Si te das cuenta, las constantes
estn definidas usando esquema jerrquico. Por ejemplo, la URI de los contactos se seala
como Contacts.People.CONTENT_URI. Esto se debe a que las bases de datos de contactos
pueden tener muchas tablas para representar la entidad de un contacto. People es una de las
tablas o colecciones. Cada entidad primaria de una base de datos puede llevar su propia
URI de contenido.
En Contacts.Pople.CONTENT_URI, Contacts es un paquete de java y People es una clase
dentro de ese paquete. Hay que saber que Contacts y Contacts.People estn obsoletos desde
Android 2.0 y que ahora poseen nuevas URIs equivalentes que veremos ms adelante. Sin
embargo, para propositos educativos podemos seguir usandolos aunque estn obsoletos.
Dadas estas URIs, el cdigo para recuperar una nica fila del proveedor de contactos sera:
Uri uriBase = Contacts.People.CONTENT_URI;
Uri uriPersona = Uri.withAppendedPath(Contacts.People.CONTENT_URI, "21");
//Consultamos el registro
//managedQuery es un mtodo de la clase Activity
Cursor c = managedQuery(uriPersona, null, null, null);
// Clusula where
PROGRAMACIN ANDROID:
USANDO CURSORES
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Todos los mtodos de acceso a los campos se basan en nmeros de columnas, por lo
que se necesita convertir el nombre de la columna a un nmero.
El cursor tiene unos mtodos que nos permiten navegar por l. A continuacin vemos como
comprobar si el cursor est vaco y cmo navegar por l fila a fila en caso de no estarlo.
if (cur.moveToFirst() == false){
//el cursor est vaco
return;
}
//El cursor ahora apunta a la primera fila
// Accedemos a las columnas
int nameColumnIndex = cur.getColumnIndex(People.NAME);
String name = cur.getString(nameColumnIndex);
En el ejemplo de arriba se asume que el cursor est posicionado antes de la primera fila.
Para posicionarlo en la primera fila usamos moteToFirst(). Este mtodo devuelve false si el
cursor est vaco. Despus usamos moveToNext()repetitivamente para avanzar en el cursor.
Para ayudarnos a saber donde se encuentra el cursor, Android proporciona los siguientes
mtodos:
isBeforeFirst()
isAfterLast()
isClosed()
Haciendo uso de estos mtodos podemos recorrer el cursor con un for en lugar de con
un while:
// Obtenemos los ndices de las columnas
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
//Recorremos el cursor
for(cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()){
String name = cur.getString(nameColumn);
String phoneNumber = cur.getString(phoneColumn);
Por ltimo, para obtener el nmero de registros que hay en el cursor, podemos usar el
mtodo getCount().
PROGRAMACIN ANDROID:
USANDO LA CLUSULA
WHERE
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Los proveedores de conteido ofrecen dos formas de pasar una clusula where:
A travs de la URI
Activity activity;
//... Inicializamos la actividad...
String siteUri = "content://com.elbauldelprogramador.provider.FavSites/sites/23";
Cursor managedCursor = activity.managedQuery( siteUri,
projection, //Columnas a devolver
null,
//Clusula WHERE
null);
//Clusula ORDER BY
En este ejemplo se ha dejado el argumento que hace referencia a la clusula where a null ya
que hemos especificado el ID del registro que queremos en la URI. En este caso el ID est
embebido en la URI. Se usa la URI como vehculo para pasar la clusula where. Esto se
hace evidente cuando nos fijamos cmo se implementa el proveedor para los Sites de la
aplicacin, que corresponde al mtodo query. A continuacin un fragmento de cdigo del
mtodo query:
//Devuelve un id de sitio
//content://.../sites/23
int siteId = uri.getPathSegments().get(1);
queryBuilder.setTables(favSitesTableMetaData.TABLE_NAME);
queryBuilder.appendWhere(favSitesTableMEtaData._ID + "=" + siteId);
Como vemos la id del sitio se extrae de la URI. La Uri se divide en segmentos (path) del a
forma content:///seg1/seg2/seg3, en nuestro ejemplo el primer segmento es el id 23.
Las clases Uri y UriMatcher se usan para identificar las URIs y extraer parmetros de ellas,
ms adelante las veremos. SQLiteQueryBuilder es una clase asistente en
android.database.sqlite que permite construir consultas SQL que se ejecutarn por
SQLiteDatabase en una instancia de una base de datos SQLite.
El parmetro selection, es el que acta como clusula Where (Representa un filtro en el que
elegimos qu filas queremos que se nos devuelvan). Si en este argumento pasamos null se
nos devolvern todas las filas para la URI dada. En este parmetro podemos incluir ?, que
sern reemplazados por los valores del parmetro selectionArgs en el orden que vayan
apareciendo.
Te preguntars qu mtodo usar en segn que situacin. Por convencin se suele usar el
mtodo mediate URI cuando sea posible aplicarlo, y el explcito en casos especiales (Como
en el ejemplo de arriba.)
PROGRAMACIN ANDROID:
INSERTANDO REGISTROS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 2 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Todo lo que necesitamos en este punto es una URI para decirle al ContentResolver que
inserte la fila. En entradas anteriores vimos que nuestra URI era:
content://com.elbauldelprogramador.provider.FavSites/sites
Con esta URI y nuestro ContentValues podemos ahora hacer una llamada para insertar
nuestra fila:
Uri uri = cr.insert(FavSitesProviderMetaData.CONTENT_URI, cv);
La lnea anterior devuelve una uri apuntando al nuevo registro aadido, la URI devuelta se
parecer a esto:
FavSitesProviderMetaData.CONTENT_URI/Nuevo_ID
Con esta Uri, podemos por ejemplo mostrar en el log del sistema qu registro hemos
aadido:
Log.d("Nuevo registro aadido","Uri:" + insertedUri);
Para poder realizar estas operaciones necesitamos crear una columna adicional llamada
_data, hacer una llamada al mtodo insert para obtener una URI. EL siguiente cdigo
demuestra como se hara:
ContentValues cv = new ContentValues();
cv.put("NombreColumna1", "valor1");
cv.put("NombreColumna2", "valor2");
//Usamos el content resolver para insertar un registro
ContentResolver cr = miActivity.getContentResolver();
Uri nuevaUri = cr.insert(FavSitesProviderMetaData.CONTENT_URI, cv);
Una vez tenemos la uri del registro, pedimos a ContentResolver que obtenga una referencia
al output stream del archivo:
//Usamos el ContentResolver para obtener el output stream directamente
//El content resolver oculta el acceso al campo _data donde se almacena realmente la referencia
al archivo
OutputStream outStream = miActivity.getContentResolver().openOutputStream(nuevaUri);
algunArchivoDeImagen.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
outStream.close;
PROGRAMACIN ANDROID:
ACTUALIZAR Y BORRAR
REGISTROS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 1 C O M M E N T ,
IN ANDROID, OPENSOURCE
Vimos cmo insertar registros y consultarlos, bien, pues actualizar y borrar registros es
bastante sencillo. Realizar unupdate (Actualizar registros) es muy similar a hacer una
insercin, en la cual los valores de la columna a modificar se pasan mediante un
objeto ContentResolver. Abajo se muestra una sentencia para realizar dicho update:
int numeroDeLineasActualizadas =
activity.getContentResolver().update(
Uri uri,
ContentValues values,
String whereClause,
String[] selectionArgs )
Uri uri,
String whereClause,
String[] selectionArgs )
PROGRAMACIN ANDROID:
IMPLEMENTANDO UN
CONTENT PROVIDER (PARTE
1)
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Esta es la primera entrada de un total de 4 en la que se irn describiendo los pasos a dar
para crear nuestro propio proveedor de contenidos.
Ya hemos visto cmo interactuar con un Content provider, pero no hemos visto an cmo
escribir nuestro propio Content Provider. Para hacerlo, es necesario extender
deandroid.content.ContentProvider e implementar los siguientes mtodos:
query
insert
update
delete
getType
Tambin necesitamos configurar unas cuantas cosas antes de implementarlo. Los paso a
seguir para implementarlo son los siguientes:
1.
2.
3.
4.
//
//This file is part of FavSites.
//
//
//
//
//
//
// FavSites is distributed in the hope that it will be useful,
//
//
//
//
//
You should have received a copy of the GNU General Public License
//
package com.elbauldelprogramador.favsites.provider;
import android.net.Uri;
import android.provider.BaseColumns;
/**
* @author Alejandro Alcalde
* Definiciones necesarias para almacenar la informacin
*/
public class FavSitesProviderMetaData {
public static final String AUTHORITY = "com.elbauldelprogramador.provider.FavSites";
public static final String DATABASE_NAME = "favsites.db";
public static final int DATABASE_VERSION = 1;
public static final String FAVSITES_TABLE_NAME = "favSites";
private FavSitesProviderMetaData() {}
/**
* Clase interna para describit la tabla favSites
*/
public static final class favSitesTableMEtaData implements BaseColumns{
private favSitesTableMEtaData() {}
public static final String TABLE_NAME = "favSites";
/**
* DEfinicin del Content URI y MIMEs
*/
public static final Uri CONTENT_URI
= Uri.parse("content://" + AUTHORITY + "/sites");
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.favsites.site";
public static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.favsites.site";
/**
* Orden por defecto de la tabla
*/
public static final String DEFAULT_SORT_ORDER = "_ID DESC";
/**
* Orden personalizado
*/
Despues procedemos a definir una tabla (favSites) como una clase interna
deFavSitesProviderMetaData. Posteriormente, la clase favSitesTableMEtaData define una
URI para identificar las colecciones de stios. Dada la authority del prrafo anterior, la URI
para una coleccin de stios ser como la siguiente:
content://com.elbauldelprogramador.provider.FavSites/sites
La clase favSitesTableMEtaData define los MIME types para una coleccin de sitios y de
un nico stio. La implementacin del proveedor usar estas constantes para devolver los
MIME types para las URIs entrantes.
favSitesTableMEtaData tambin declara un conjunto de columnas: nombre, descripcin,
latitud, longitud y foto.
Es aconsejable describir los tipos de datos que poseen las columnas mediante comentarios.
Adems, la clase favSitesTableMEtaData hereda de la clase BaseColumns, la cual
proporciona el campo estandar _ID, que representa el identificador de la fila. Con todas
estas definiciones de metadatos, estamos listos para continuar con la implementacin de
nuestro proveedor.
PROGRAMACIN ANDROID:
IMPLEMENTANDO UN
CONTENT PROVIDER (PARTE
1)
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Esta es la primera entrada de un total de 4 en la que se irn describiendo los pasos a dar
para crear nuestro propio proveedor de contenidos.
Ya hemos visto cmo interactuar con un Content provider, pero no hemos visto an cmo
escribir nuestro propio Content Provider. Para hacerlo, es necesario extender
deandroid.content.ContentProvider e implementar los siguientes mtodos:
query
insert
update
delete
getType
Tambin necesitamos configurar unas cuantas cosas antes de implementarlo. Los paso a
seguir para implementarlo son los siguientes:
1.
2.
3.
4.
//
//This file is part of FavSites.
//
//
//
//
//
//
// FavSites is distributed in the hope that it will be useful,
//
//
//
//
//
You should have received a copy of the GNU General Public License
//
package com.elbauldelprogramador.favsites.provider;
import android.net.Uri;
import android.provider.BaseColumns;
/**
* @author Alejandro Alcalde
* Definiciones necesarias para almacenar la informacin
*/
public class FavSitesProviderMetaData {
public static final String AUTHORITY = "com.elbauldelprogramador.provider.FavSites";
public static final String DATABASE_NAME = "favsites.db";
public static final int DATABASE_VERSION = 1;
public static final String FAVSITES_TABLE_NAME = "favSites";
private FavSitesProviderMetaData() {}
/**
* Clase interna para describit la tabla favSites
*/
public static final class favSitesTableMEtaData implements BaseColumns{
private favSitesTableMEtaData() {}
public static final String TABLE_NAME = "favSites";
/**
* DEfinicin del Content URI y MIMEs
*/
public static final Uri CONTENT_URI
= Uri.parse("content://" + AUTHORITY + "/sites");
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.favsites.site";
public static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.favsites.site";
/**
* Orden por defecto de la tabla
*/
public static final String DEFAULT_SORT_ORDER = "_ID DESC";
/**
* Orden personalizado
*/
Despues procedemos a definir una tabla (favSites) como una clase interna
deFavSitesProviderMetaData. Posteriormente, la clase favSitesTableMEtaData define una
URI para identificar las colecciones de stios. Dada la authority del prrafo anterior, la URI
para una coleccin de stios ser como la siguiente:
content://com.elbauldelprogramador.provider.FavSites/sites
La clase favSitesTableMEtaData define los MIME types para una coleccin de sitios y de
un nico stio. La implementacin del proveedor usar estas constantes para devolver los
MIME types para las URIs entrantes.
favSitesTableMEtaData tambin declara un conjunto de columnas: nombre, descripcin,
latitud, longitud y foto.
Es aconsejable describir los tipos de datos que poseen las columnas mediante comentarios.
Adems, la clase favSitesTableMEtaData hereda de la clase BaseColumns, la cual
proporciona el campo estandar _ID, que representa el identificador de la fila. Con todas
estas definiciones de metadatos, estamos listos para continuar con la implementacin de
nuestro proveedor.
PROGRAMACIN ANDROID:
IMPLEMENTANDO UN
CONTENT PROVIDER (PARTE
3)
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Ya hemos visto como plantear la base de datos para un proveedor y cmo implementar
parte del proveedor de contenidos, en esta tercera parte vamos a implementar los mtodos
query, insert, update, delete y getType.
En el cdigo que vimos en la anterior entrada, se implementa el mtodo getType(), que
devuelve los tipos MIME para una URI dada. Este mtodo, al igual que muchos de los
mtodos del content provider, est sobrecargado con respecto a la URI entrante. La funcin
de este mtodo consiste en distinguir el tipo de URI. Para saber si es una coleccin de
lugares (en el caso de la aplicacinFavSites), o un nico lugar.
El mtodo query usa las proyecciones (projecttions) que creamos para identificar las
columnas devueltas. Bsicamente, query devuelve un cursor. Durante la llamada al mtodo
query, se usa el objeto SQLiteQueryBuilder para formular y ejecutar la consulta.
IMPLEMENTACIN DEL MTODO INSERT
ste mtodo se encarga de insertar registros en la base de datos y devuelve una URI que
apunta al registro insertado. Al igual que el mtodo anterior, usa UriMatcher para
identificar el tipo de URI. Primero comprueba si la URI coincide correctamente con el tipo
de coleccin de datos de dicha URI. Si esta comprobacin falla, se lanza una excepcin.
A continuacin, se validan los parmetros correspondientes a las columnas opcionales y
obligatorias. Es posible asignar valores por defecto a ciertas columnas si no se pas su valor
como parmetro.
Despus, se usa el objeto SQLiteDatabase para insertar el nuevo registro y devolver el ID
que se acaba de insertar. Por ltimo, se crea una URI nueva a partir del ID devuelto por la
base de datos.
IMPLEMENTACIN DEL MTODO UPDATE
Se encarga de actualizar registros que cumplan las condiciones que establece laclusula
where. ste mtodo devuelve el nmero de registros actualizados.
Tambin usa UriMatcher para identificar el tipo de URI. Si la URI es una coleccin de
datos, se aplica la clusula where para aplicar el update a los registros que cumplan las
condiciones de dicha clusula. Si por el contrario, el tipo de URI es de un solo registro, se
extrae el ID (En este caso de un lugar) de la URI y se especifica como una clusula where
adicional para identificar el lugar almacenado en la base de datos que tenga asignado ese
ID. Una vez acabado el proceso de actualizar los registros, Update devuelve el nmero de
registros que se modificaron.
INCOMING_SINGLE_SITE_URI_INDICATOR);
}
Conciendo esta implementacin, ahora es ms fcil saber cmo usan los otros mtodos el
UriMatcher, por ejemplo, el mtodo query:
switch (sUriMatcher.match(uri)) {
case INCOMING_SITE_COLLECTION_URI_INDICATOR:
//...
break;
case INCOMING_SINGLE_SITE_URI_INDICATOR:
//...
break;
default:
throw new IllegalArgumentException("Unknow URI " + uri);
}
Como se aprecia en el cdigo de arriba, el mtodo match devuelve el msmo nmero que
hemos registrado en el paso anterior.El constructor de UriMatcher toma un entero que se
usar para la raiz de la URI, se devolver dicho nmero si en la URL no existen segmentos
en el path o authorities. Tambin devolver la constante NO_MATCH cuando los patrones
no coincidan. Es posible crear un UriMatcher sin un identificador para la raiz de la URI, en
tal caso, Android inicializar UriMatcher a NO_MATCH internamente. Por lo tanto, el
cdigo que se muestra a continuacin es equivalente al anterior:
static {
sUriMatcher = new UriMatcher();
sUriMatcher.addURI(FavSitesProviderMetaData.AUTHORITY, "sites",
INCOMING_SITE_COLLECTION_URI_INDICATOR);
sUriMatcher.addURI(FavSitesProviderMetaData.AUTHORITY, "sites/#",
INCOMING_SINGLE_SITE_URI_INDICATOR);
}
Si leemos la documentacin del mtodo joins. Por ejemplo, podra asignar nombre a
people.name. Si un mapa de proyeccin se configura para que deba contener todos los
nombres de las columnas que el usuario pueda solicitar, aunque la clave y el valor sean los
mismos.
En nuestro ejemplo, as es como se a configurado el projection map:
private static HashMap<string , String> sSitesProjectionMap;
static{
sSitesProjectionMap = new HashMap</string><string , String>();
sSitesProjectionMap.put(favSitesTableMEtaData._ID,
favSitesTableMEtaData._ID);
//nombre, desc, lati, long, foto
sSitesProjectionMap.put(favSitesTableMEtaData.NAME,
favSitesTableMEtaData.NAME);
sSitesProjectionMap.put(favSitesTableMEtaData.DESCRIPCION,
favSitesTableMEtaData.DESCRIPCION);
sSitesProjectionMap.put(favSitesTableMEtaData.LATITUD,
favSitesTableMEtaData.LATITUD);
sSitesProjectionMap.put(favSitesTableMEtaData.LONGITUD,
favSitesTableMEtaData.LONGITUD);
sSitesProjectionMap.put(favSitesTableMEtaData.FOTO,
favSitesTableMEtaData.FOTO);
}
</string>
PROGRAMACIN ANDROID:
IMPLEMENTANDO UN
CONTENT PROVIDER (PARTE
4)
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
En esta ltima parte de una serie de 4 artculos en los que se ha ido explicando cmo
implementar un ContentProvider desde cero, se va a ver cmo registrar dicho proveedor y
cmo darle uso.
REGISTRAR EL PROVEEDOR
AADIR REGISTROS
String tag = "Insertando registros...";
ContentValues cv = new ContentValues();
Log.d(tag,"Adding a site...");
cv.put(FavSitesProviderMetaData.favSitesTableMEtaData.NAME,
"NombreSitio");
cv.put(FavSitesProviderMetaData.favSitesTableMEtaData.DESCRIPCION,
"Descripcion");
cv.put(FavSitesProviderMetaData.favSitesTableMEtaData.LONGITUD,
paquete.getInt("long"));
cv.put(FavSitesProviderMetaData.favSitesTableMEtaData.LATITUD,
paquete.getInt("lat"));
ContentResolver cr = getContentResolver();
Uri uri = FavSitesProviderMetaData.favSitesTableMEtaData.CONTENT_URI;
Log.d(tag,"site insert uri:" + uri);
Uri insertedUri = cr.insert(uri, cv);
Log.d(tag,"inserted uri:" + insertedUri);
ELIMINAR REGISTROS
ContentResolver cr = getContentResolver();
Uri uri = FavSitesProviderMetaData.favSitesTableMEtaData.CONTENT_URI;
Log.d("Deleting site...","site delete uri:" + uri);
cr.delete(uri,
"_ID=?",
new String[]{"5"});
Para realizar esto, debemos crear un cursor y contar el nmero de registros de este:
Uri uri = FavSitesProviderMetaData.favSitesTableMEtaData.CONTENT_URI;
Cursor cur = managedQuery(uri,
null, // projection
null, // selection strings
null, // selection args array of strings
null);// sort order
int numeroRegistros = cur.getCount();
cur.close();
Espero que este conjunto de cuatro artculos os haya servido de ayuda. En los prximos
artculos veremos en profundidad los intents.
PROGRAMACIN ANDROID:
INTENTS CONCEPTOS
BSICOS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 2 2 C O M M E N T S ,
IN ANDROID, OPENSOURCE
setContentView(R.layout.MiActivity);
}
}
El layout R.Layout.MiActivity debe estar declarado y ser un archivo de layout valido. Una
vez creado este archivo de layout, es necesario registrarlo en elAndroidManifest, que ser
algo as:
<activity android:name=".MiActivity"
android:label="Mi Activity">
<intent -filter>
<action android:name="nuestra.accion.nombreAccion"/>
<category android:name="android.intent.category.DEFAULT" />
</intent>
</activity>
ejemplo, para el navegador web, tenemos dos acciones, VIEW yWEB_SEARCH, que
abren el navegador en una url especfica o realizan una bsqueda.
En el caso del dialer (marcador), tenemos las acciones CALL y DIAL, que vienen dadas
por la URI tel:numero_de_telfono, la diferencia entre estas dos acciones, es que CALL
realiza la llamada al nmero de la URI, y DIAL solo lo marca, pero no realiza la llamada.
Vamos a ver ejemplos de intents que invocan a las aplicaciones mencionadas en la
documentacin de Android:
public static void invokeWebBrowser(Activity activity){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com"));
activity.startActivity(intent);
}
public static void invokeWebSearch(Activity activity){
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.setData(Uri.parse("http://www.google.com"));
activity.startActivity(intent);
}
public static void dial(Activity activity){
Intent intent = new Intent(Intent.ACTION_DIAL);
activity.startActivity(intent);
}
public static void call(Activity activity){
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:555-555-555"));
activity.startActivity(intent);
}
public static void showMapAtLatLong(Activity activity){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:0,0?z=4&q=restaurantes"));
activity.startActivity(intent);
}
Un intent est formado por una accin, datos (que se representan mediante URIs), datos
extra en pares clave/valor y un nombre de clase explcito, llamado nombre del componente.
Es necesario aclarar algo, cuando un intent trae consigo un nombre de componente, se le
llama intent explcito. Cuando no lo lleva y depende de la accin y los datos se llama intent
implcito.
El nombre de las acciones normalmente suele ser un String o un String constante con el
nombre del paquete como prefijo.
La seccin de datos de un intent no son datos realmente, se trata de punteros a datos. Est
representado por un string que representa una URI. Una Uri de un intent puede contener
argumentos, como las urls de las web.
ACCIONES GENRICAS
Vamos a volver a ver el cdigo que invoca al navegador web para analizarlo ms en
profundidad:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com"));
activity.startActivity(intent);
En este caso, ACTION_VEW parece una accon muy genrica, Android se las ingenia para
averiguar a qu actividad llamar en base a esta accin haciendo uso de la composicin de la
URI. Para ello, mira el esquema que posee la URI, que en este caso es http y pregunta a
todas las actividades para saber cual de ellas comprende este esquema. Por lo tanto, la
actividad del navegador deber tener registrada la accin VIEW junto con el esquema de
datos de http:
<activity ...>
<intent -filter>
<action android:name="android.intent.action.VIEW"/>
INFOMACIN EXTRA
Los intents admiten adems de las acciones y datos, un atributo adicional llamadoextras.
Este tipo de dato viene dado por la forma clave/valor, en la cual el nombre de la clave
normalmente suele empezar con el nombre del paquete y el valor puede ser de cualqueira
de los tipos fundamentales u objetos arbitrrios, siempre que se implemente la inrefaz
android.os.Parcelable. Esta informacin extra se representa mediante la
clase android.os.Bundle
//Obtener un bundle
Bundle b = intent.getExtras();
//Colocar un bundle en un intent
Bundle b2 = new Bundle();
//Rellenar el bundle con datos fundamentales
putExtra(String name, boolean value);
putExtra(String name, int value);
putExtra(String name, double value);
putExtra(String name, String value);
//Otros tipos de datos
putExtra(String name, int[] value);
putExtra(String name, float[] value);
putExtra(String name, Serializable value);
putExtra(String name, Parcelable value);
putExtra(String name, Bundle value);
//Aadir bundles de otros intents
putExtra(String name, Intent otroIntent);
//Aadir el bundle al intent
intent.putExtras(b2)
As, cualquier intent podr iniciar la actividad, pero para ello, debemos registrar dicha
actividad en el AndroidManifest as:
Sin ningn tipo de intent-filter, ya que estos no son necesarios cuando se invoca a una
actividad directamente mediante el nombre de su clase. Recordad que este intent es de tipo
explcito.
PROGRAMACIN ANDROID:
INTENTS CATEGORAS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
Vamos a ver algunas categoras predefinidas, podis encontrar la lista de todas ellas
endeveloper.android.com/reference/android/content/Intent.html#CATEGORY_ALTERNAT
IVE:
Cuando usamos un intent para iniciar una actividad podemos especificar qu tipo de
actividad queremos especificando la categora. Otra opcin es buscar las actividades que
coincidan con una determinada categora, por ejemplo:
Intent i = new Intent(Intent.ACTION_MAIN, null);
i.addCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = getPackageManager();
List<resolveinfo> list = pm.queryIntentActivities(i, 0);
</resolveinfo>
PackageManager permite encontrar actividades que coincidan con un intent sin llegar a
invocarlas. Una vez ejecutado lo de arriba, podemos iterar sobre la lista e invocar a la
actividad que coincida con el nombre que deseemos:
for(ResolveInfo ri: list){
Log.d("Info", ri.toString());
String pkgName = ri.activityInfo.packageName;
String className = ri.activityInfo.name;
if(className.equals("nombre.paquete.denuestra.actividad.nombreActividad")){
Como mencion anteriormente, en el caso de que exista ms de una actividad que satisfaga
las condiciones que impone el intent, se mostrar un dilogo al usuario para que elija cual
lanzar.
Si quisiramos invocar un intent para volver a la pantalla principal, basta con cambiar la
categora del cdigo de arriba
de Intent.CATEGORY_LAUNCHER aIntent.CATEGORY_HOME
PROGRAMACIN ANDROID:
CMO SE RESUELVEN LOS
INTENTS
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, HOW TO, OPENSOURCE
Vamos a ver que estratgias usa Android para encontrar la actividad que corresponde a un
intent basndose en los intent-filter. Para resolver este problema, se establece una jerarqua.
En el primer lugar de dicha jerarqua se encuentra el nombre del componente que se adjunta
al intent. Este tipo de intent son explcitos, y dado que ya se sabe el nombre del
componente, el resto de datos asociados al intent se ignoran. Por el contrario, cuando el
intent no disponga de nombre de componente asociado, ser un intent implcito, para este
tipo de intents hay diversas formas de encontrar la actividad correspondiente.
ACTION
Si un intent tiene una accin establecida, el intent-filter debe tener esa accin declarada o
no tener ninguna accin definida. Es decir, si una actividad no tiene declarado ningn intent
filter, se considera una opcin para cualquier intent con una accin.
DATA
Si no se especifica ningn tipo de dato en un intent-filter, ste no coincidir con ningn
intent que s que tenga establecido cualquier tipo de dato adicional. Es decir, esa actividad
solo se considerar una opcin para los intent que no tengan especificado ningn dato.
DATA TYPE
Para que se considere como coincidencia un tipo de dato, el intent debe ser uno de los tipos
de datos declarados en el intent-filter. Para determinar el tipo de dato android tiene dos
formas. La primera es determinar el tipo de dato a partir de la URI (si la URI es una content
URI) o si la URI es un fichero (file://). La segunda es mirar en el tipo de dato explcito
del intent. Para que esto funcione correctamente el intent no debe tener una URI de datos
adjunta, ya que se toma automticamente cuando llamamos al mtodo setType() en el
intent. Es posible cubrir multitud de subtipos con *.
DATA SCHEME
Para que un esquema de datos coincida (data scheme), el esquema de datos ha de estar
presente tanto en el intent como en el intent-filter de la actividad. Un esquema de datos es
la primera parte de una URI, por ejemplo, http://, file://, content://, ftp:// etc. Los intent no
tienen definido ningn mtodo para establecer el esquema de datos, ya que viene dado por
la URI del intent.
En el caso de que el esquema sea del tipo content: file:, se considera una coincidencia
independientemente de lo que se especifique en el intent-filter. Se aplica esta regla porque
cada componente debe saber como leer datos desde urls del tipo content o file, ya que son
locales al dispositivo.
DATA AUTHORITY
En el caso de que no se especifique authority alguno en el intent-filter, se obtendr una
coincidncia para cualquier data URI authority. Si por el contrario se especifica en el intentfilter, como ejemplo pongamos www.elbauldelprogramador.org, entonces se considerar
una coincidencia un esquema de datos y una authority.
Un ejemplo fcil para comprender esto podra ser que tengamos esto declarado como
authority en el intent-filter www.elbauldelprogramador.org, y como esquema de datos https,
todo intent fallar si usamos lo siguiente, /path, ya que el esquema de datos http no est
declarado.
DATA PATH
Ningn path (ruta) especificado en el intent-filter resultar ser una coincidencia para
cualquier path entrante. Para validar un intent, el esquema de datos, el authority y el path
trabajan juntos. Es decir en http://elbauldelprogramador.org/pathlos tres trabajan juntos
para validar el intent.
INTENT CATEGORIES
Cada categora debe estar presente en el intent-filter. En el caso de que en el intent-filter no
exista ninguna categora especificada, esa actividad solo ser una coincidencia para los
intent que no tengan ninguna categora especificada. Sin embargo, hay que tener en cuenta
que los intent implcitos que se pasanstartActivity() contienen al menos una categora que
es android.intent-category.DEFAULT. Por lo tanto, hemos de tener en cuenta que si
queremos llamar a una actividad mediante un intent implcito debemos registrar dicha
categora en el intent-filter.
Si una actividad no tiene declarada la categora por defecto, pero conocemos su nombre de
componente, podmos llamarle mediante un intent explcito.
PROGRAMACIN ANDROID
EJEMPLO DE USO DE
ACTION_PICK
2 0 1 4 / 0 9 / 11/ B Y A L E J A N D R O AL C A L D E , 0 C O M M E N T S ,
IN ANDROID, OPENSOURCE
La idea de ACTION_PICK es lanzar una actividad que muestre una liste de objetos a
seleccionar para que el usuario elija uno de ellos. Una vez elegido, la actividad devuelve la
URI del elemento elegido. As se permite reusar la interfaz grfica.
Se debe indicar usando MIME types la coleccin de datos que vamos a usar, el cual
apuntar a un cursor parecido a este:
vnd.android.cursor.dir/vnd.favsites.site
if (resultCode != Activity.RESULT_OK){
Log.d("test", "ResultCode no es OK: " + resultCode);
return;
}
Log.d("Test", "Resulcode es OK:" + resultCode);
Uri selectedUri = outputIntent.getData();
Log.d("test", "La uri de salida:" + selectedUri.toString());
//Mostramos la nota
outputIntent.setAction(Intent.ACTION_VIEW);
startActivity(outputIntent);
}
= -1;
= 0;
RESULT_FIRST_USER = 1;
Por otro lado, en la aplicacin notePad, debe haber un cdigo devuelva un valor en el caso
de que se haya llamado a la actividad desde un intent con ACTION_PICK como accin:
@Override
protected void onListItemClick(ListView l, View v, int position, long id){
Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
String action = getIntent().getAction();
if(Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action))
//devolvemos la nota seleccionada
setResult(RESULT_OK, new Intent().setData(uri));
else
//Lanzamos una actividad para ver, editar la nota
startActivity(new Intent(Intent.ACTION_EDIT, uri));
}