Tabla de Contenidos

Android

General

Instalación

Para desarrollar una aplicación para android necesitaremos tener:

  1. Eclipse
  2. El SDK de Android
  3. Instalar el plugin para eclipse de desarrollo de Android.

La web oficial de desarrollo en Android es http://android-developers.blogspot.com/index.html.

Arquitectura

La arquitectura de Android está estructurada por capas y cada capa utiliza los servicios de las que tiene por debajo. Las capas empezando por la más baja son:

El ciclo de vida de una aplicación

Android trabaja únicamente con una aplicación a la vez (que no proceso), por ejemplo, al iniciar el sistema se inicia la aplicación Home (con menús, reloj, mensajes para el usuario…); cuando el usuario inicia otra aplicación la Home queda en segundo plano y, por lo tanto, recibe menos “atención”. A medida que se van iniciando aplicaciones estas son guardadas en la pila de aplicaciones (application stack) por el activity manager. El usuario podrá volver a la aplicación anterior como si de una navegación web se tratase.

Cada entorno (ventana, aplicación…) está representada por una clase Activity. Una aplicación realmente es una (o más) Activity enlazada a un proceso Linux, pero la aplicación no queda finalizada aunque el proceso Linux lo esté.

Las activities permanecen en un estado controlado por el sistema, no por el programador. Cuando el estado cambia avisa a la activity mediante eventos pudiendo ser las transiciones de la siguiente forma:

Es decir, se han de implementar los siguientes métodos y el sistema los llamará en el momento adecuado:

Las aplicaciones deberían guardar su estado en el método onPause debido a que no se sabe si continuarán en ejecución en un futuro.

Bloques de desarrollo

Existen distintos tipos de bloques que el usuario puede aprovechar (heredando de ellos) en su código:

Permisos

En el fichero llamado Android-Manifest.xml se indica a qué partes del sistema accederá la actividad y será el Package Manager quien dará esos permisos a partir de la aceptación del usuario.

Un ejemplo del código en el Android-Manifest.xml es el siguiente que da la posivilidad de acceder a los SMS:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.app.myapp" >
  <uses-permission android:name="android.permission.RECEIVE_SMS" />
</manifest>

Interfaces de usuario

Cuando creamos un proyecto con Eclipse mediante la SDK de Android se generan varios directorios, entre ellos el res que contiene los recursos. Estos pueden ser archivos xml con textos que se utilicen en la aplicación, o xml que representen layouts (interficie), o sonidos, gráficos, iconos… Cuando se compila el proyecto aparece otro directorio, gen, el cual contiene la clase generada R que corresponde a los recursos y que, a su vez, contiene los identificadores (variables int estáticas) de los recursos creados.

Cuando utilizamos archivos xml como recursos de un proyecto Android estos han de comenzar con la siguiente declaración:

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

Layouts

Los layouts son contenederes para objetos hijo, su función es posicionar estos objetos en la pantalla. Los más comunes son:

Los parámetros comunes para ellos:

Para indicar un layout especial para el momento en el que se gire el teléfono crearemos una nueva carpeta, la layout-land, y en ella insertaremos los xml correspondientes, por ejemplo el main.xml.

Otros contenedores

Pero los layouts no son los únicos contenedores (ni tampoco los primeros que se han de poner en una aplicación). Por ejemplo, si queremos que un entorno tenga scroll añadiremos:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:background="@color/background" >
 
  <LinearLayout 
    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/app_name" android:gravity="center" android:textColor="@color/green"/>
 
    <Button
      android:id = "@+id/btnState"
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:text="@string/State"/>
 
  </LinearLayout>
</ScrollView>

Es decir…

Controles dentro del layout

En una layout podemos añadir elementos, estos serán tags xml y se agregarán de la siguiente:

<?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/app_name"/>
</LinearLayout>

Para acceder a un control mediante código necesitamos indicar un identificador, para ello utilizamos la propiedad android:id=“@+id/identificador”. Esto hará que en la clase R se cree un identificador para ese elemento.

<TextView  
    android:id="@+id/text_view1"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/app_name"/>

Propiedades comunes

Lista de controles

Recursos

Un recurso es la parte de la aplicación que no es código (por ejemplo imagenes, sonidos, textos…) pero que se compilan con esta. Han de guardarse en el directorio res de la aplicación. Cuando lo hacen se crea una clase denominada R que contiene los identificadores a cada uno de los recursos para poder acceder a estos desde el código, para ello en el directorio res se crean subdirectorios, como por ejemplo el layout y dentro de este archivos como por ejemplo el main.xml, que sería el layout principal. Para acceder a este layout haríamos R.layout.main. La clase R la maneja automáticamente Eclipse.

Strings

Dentro del proyecto, en la carpeta res encontraremos la subcarpeta values con el fichero string.xml. Este corresponde a los textos de la aplicación.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, Test!</string>
    <string name="app_name">Test</string>
    <string name="OnState">Apagar</string>
    <string name="OffState">Encender</string>
</resources>

Podemos añadir código en formato html y con multilinia colocando el carácter \ al inicio:

    <string name="about_text"> \ 
    Un <b>recurso</b> es la parte de la aplicación que no es código (por ejemplo imagenes, sonidos, textos…) 
    pero que se compilan con esta. Han de guardarse en el directorio res de la aplicación. Cuando lo 
    hacen se crea una clase denominada R que contiene los identificadores a cada uno de los recursos 
    para poder acceder a estos desde el código, para ello en el directorio res se crean subdirectorios, 
    como por ejemplo el layout y dentro de este archivos como por ejemplo el <i>main.xml</i>, que sería el layout 
    principal. Para acceder a este layout haríamos <i>R.layout.main</i>. La clase R la maneja automáticamente Eclipse. 
    </string>

Otros

Por ejemplo colores, agregamos el fichero res\values\colors.xml y le añadimos el siguiente contenido:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="red">#BA030E</color>
    <color name="green">#1D7900</color>
    <color name="background">#EDF5FF</color>
    <color name="black">#000000</color>
</resources>

Ahora en las propiedades que acepten colores podremos asignar estos valores como @color/black, por ejemplo.

Más...

String[] countries = getResources().getStringArray(R.array.countries_array);

Activity

Las activities son lo equivalentes a “ventanas” dentro de nuestra aplicación.
Para agregar una Activity a nuestra aplicación necesitamos:

  1. Una layout. Agregariamos el archivo .xml en /res/layout/ correspondiente.
  2. Una clase java que herede de android.app.Activity.
  3. Agregarla al AndroidManifest.xml.
  4. Lanzar la Activity a partir de un Intent.

Clase Activity

La siguiente sería una clase que hereda de Activity:

package my.test;
 
import android.app.Activity;
import android.os.Bundle;
 
public class About extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.about);
	}
}

Para agregarla al AndroidManifest.xml abriremos el archivo y añadiremos la siguiente línea dentro de la tag application:

<activity android:name=".About" android:label="@string/State" />

Siendo About el nombre de la clase y State el título que queramos darle.
Cuando una clase Activity llamaremos al setContentView para indicar su layout.

package my.test;
 
import android.app.Activity;
import android.os.Bundle;
 
public class Test extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

Abriendo Activities

Para iniciar una Activity necesitaremos utilizar un objeto Intent y lo haremos a partir de los siguientes métodos:

Para pasar argumentos entre objetos Activity utilizaremos la clase android.os.Bundle, en esta podemos agregar información (mediante el método ) y recogerla (mediante ).
Por ejemplo una Activity A va a abrir una Activity B, para enviarle información a esta haremos:

Bundle b = new Bundle();
String strValue = "Test";
b.putString("elements", strValue);
b.putInt("type", Main.AskClient);
Intent i = new Intent(this, OpenVideo.class);
i.putExtras(b);
this.startActivityForResult(i, 0);

Al crearse la Activity B lo primero que hace es mirar los datos pasados:

this.type = this.getIntent().getExtras().getInt("type");

Una vez que ha hecho todo lo que tiene que hacer devuelve la información en otro Bundle:

Bundle bundle = new Bundle();
bundle.putInt("selected", arg2 - 1);
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
this.finish();

Y en el onActivityResult de la Activity A:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (resultCode != RESULT_OK)
		return;
	Bundle bundle = data.getExtras();		
	int type = bundle.getInt("type");

Métodos y propiedades de las Activity

Intent

Los android.content.Intent son los que lanzan objetos Activity. Desde un objeto Activity crearemos un objeto Intent, en su constructor indicaremos el objeto que lo crea (this) y el objeto Class correspondiente a la clase Activity que queramos lanzar.

Intent i = new Intent(this, About.class);
this.startActivity(i);

Vistas

ListView

Muestran en una Activity una lista de elementos. Existe la Activity especial para mostrar estas llamada ListActivity, por lo tanto si queremos crear una lo que haremos será agregar una clase que herede de esta. Para rellenarla necesitaremos utilizar objetos ListAdapter que corresponden a listas\arrays que le agregaremos, para recoger cuando se ha hecho click sobre un elemento utilizaremos el método setOnItemClickListener de la lista interna que recogeremos mediante getListView():

public class OpenVideo extends ListActivity implements OnItemClickListener {
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		String param = this.getIntent().getExtras().getString("elements");
		String[] elems = param.split("\\?");
		setListAdapter(new ArrayAdapter<String>(this, R.layout.openvideo, elems));
		android.widget.ListView lv = this.getListView();
		lv.setOnItemClickListener(this);
	}
	public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
		Bundle bundle = new Bundle();
		bundle.putInt("selected", arg2);
		setResult(RESULT_OK, mIntent);
		this.finish();
	}
}

Por lo demás, al ser una Activity tendremos que agregarla al AndroidManifest.xml y crear su layout:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="16sp" >
</TextView>

Interactuar mediante Java

Acceder a los elementos

Para acceder a los elementos desde un método de una clase Activity utilizaremos el findViewById() pasándole por parámetro el id asignado (mediante la clase R), nos devolverá un objeto View:

View continueButton = this.findViewById(R.id.continue_button);
continueButton.setOnClickListener(this);

Capturar eventos

Para capturar el click en un botón, por ejemplo, debemos asignar un objeto android.view.View.OnClickListener. al método setOnClickListener.

View btn = this.findViewById(R.id.btnState);
btn.setOnClickListener(this);

La clase donde se haga esto, evidentemente deberá implementar la interfaz OnClickListener.
Luego, el en método onClick:

@Override
public void onClick(View arg0) {
  switch (arg0.getId())
  {
  case R.id.btnState:
    android.content.Intent i = new Intent(this, About.class);
    startActivity(i);
    break;
  }
}

Como... (en controles)

... Funcionan los tamaños

En Android existen varios tipos de medidas:

Es aconsejable utilizar sp para los textos y dip para todo lo demás.

... Crear mensajes

Son los más sencillos, muestran un mensaje en la parte de abajo de la pantalla:

Toast.makeText(this.getApplicationContext(), "Recuerda inicializar la wifi!!", Toast.LENGTH_LONG).show();

Programando aplicaciones

Temas

Los temas son como los CSS pero aplicados a los controles. Podemos definir los nuestros (en res/values/styles.xml), pero ya existen predefinidos.
Para indicar un tema para un objeto Activity en su tag correspondiente del AndroidManifest.xml agregaremos android:theme=“”.
Si vamos a agregar un estilo predefinido haremos el valor será: @android:style/estilo.

<activity android:name=".About" android:label="@string/State" android:theme="@android:style/Theme.Dialog" />

Temas predefinidos

Android permite mostrar dos tipos de menús, el primero es el que aparece al pulsar sobre la tecla Menu (menú de opciones), el segundo tras dejar apretado el dedo sobre la pantalla.

Este menú lo guardaremos en el fichero res/menu/menu.xml. Y será del siguiente estilo:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
	<item android:id="@+id/item01" android:title="@string/Volume" />
	<item android:id="@+id/item02" android:title="@string/Mute" />
</menu>

Para hacerlo aparecer necesitaremos sobreescribir el método onCreateOptionsMenu de la Activity, este se llama cada vez que se pulsa la tecla física Menu. Para llamarlo utilizaremos un objeto la clase MenuInflater (recogeremos el objeto de esta mediante el método getMenuInflater) llamando al método inflate:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	android.view.MenuInflater inflater = this.getMenuInflater();
	inflater.inflate(R.menu.menu, menu);
	return super.onCreateOptionsMenu(menu);
}

Para detectar qué elemento se ha pulsado sobreescribiremos el onOptionsItemSelected:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId())
	{
	case R.id.item01: 
		break;
	}
	return super.onOptionsItemSelected(item);
}

Preferencias

Las preferencias realmente son clases android.preference.PreferenceActivity y estas, como su nombre indica, heredan de Activity, utilizan un layout diferente a otras Activity. Como tal, para abrir unas preferencias necesitaremos un Intent:

startActivity(new Intent(this, Settings.class));

Este abre la clase Settings, que hereda de Activity que a su vez se enlaza al xml mediante el método addPreferencesFromResource:

package my.test;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class Settings extends PreferenceActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		addPreferencesFromResource(R.xml.settings);
	}
}

Y a la vez también necesitamos agregarla en el AndroidManifest.xml:

<activity android:name="Settings" android:label="@string/State" />

Lo que cambia más en cuanto a una Activity común es el fichero xml que colocaremos en res/xml/settings.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
	xmlns:android="http://schemas.android.com/apk/res/android">
	<CheckBoxPreference
		android:key="music"
		android:title="@string/Play"
		android:summary="@string/Stop"
		android:defaultValue="true" />
</PreferenceScreen>

En él podemos utilizar elementos que luego podrán ser preguntados a partir de su propiedad key, en el antiguo caso sólo hay un CheckBox y su key es music.
Los elementos que podemos encontrar son:

Para leer los valores lo haremos utilizando el android.preference.PreferenceManager de la siguiente forma:

boolean b = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean("music", true);

Al método getBoolean se le pasa el key de una setting boolean y, si no estubiese definida, su valor por defecto.

Estados de una aplicación

Guardar\Cargar datos

Log

El SDK de Android agrega un visor de mensajes de log del teléfono (Window → Show View → Other → Android → LogCat). Este muestra los errores de las aplicaciones, pero además podemos escribir en él mediante la clase Log:

Como...

Minis

Notas

El emulador

En un dispositivo físico

Para poder debugar desde el teléfono necesitaremos instalar los drivers.

Drivers desde Ubuntu

Creamos el siguiente archivo.

nano /etc/udev/rules.d/51-android.rules

Escribimos lo siguiente.

SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"

Y el siguiente comando para activar el driver:

chmod a+r /etc/udev/rules.d/51-android.rules

Aunque en otros he visto: chmod a+rx /etc/udev/rules.d/51-android.rules

Herramientas