Herramientas de usuario

Herramientas del sitio


fw:android

¡Esta es una revisión vieja del documento!


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 kernel de Linux, la capa que permite la comunicación con el hardware.
  • Librerías nativas, escritas en C\C++ y compiladas para cada arquitectura de cada teléfono. Entre ellas:
    • El surface manager, el administrador gráfico que gestiona el entorno, las ventanas y las aplicaciones. Interactuar con él es más sencillo que diréctamente con el hardware.
    • Las librerías de gráficos 2d y 3d.
    • Códecs multimedia, así como AAC, MP3, MPEG4…
    • SQLite, que gestiona las bases de datos internas.
    • El motor html (webkit), para mostrar archivos de páginas web.
  • El motor de Android, compuesto básicamente por la Dalvik VM, esta es una versión de Java optimizada para móviles diseñada por Google. Esta corre archivos .dex en vez de .jar, pero a su vez también hace uso de algunas librerías de Java. Una comparación con Java es que:
    • Utiliza la sintaxis de Java5.
    • El uso de doubles o floats es emulado por software.
    • El uso de threads también es limitado, no se deberían de utilizar más de 2.
    • Mejor que utilizar el finalize es utilizar los métodos close o terminate.
    • De las librerías de java hay algunas que estan soportadas (java.awt.font, java.io, java.lang, java.math…) y otras que no (java.applet, java.beans, javax.print, javax.sound…).
    • Otras librerías de terceros también son soportadas: org.apache.http, orj.json, org.xml.sax, org.xmlpull.v1.
  • El framework de aplicaciones, utilizado para programar para Android dándonos una serie de bloques de código para utilizar en nuestro desarrollo. Entre ellos encontramos:
    • El activity manager, que controla el ciclo de vida de las aplicaciones.
    • Proveedores de contenido, código para acceder a los datos contenidos en el teléfono (por ejemplo los contactos).
    • El resource manager, que gestiona los elementos de un programa que no son código (imágenes, audio…).
    • El location manager, para conocer la ubicación del teléfono.
    • El notification manager, encargado de mostrar alertas y al usuario.
    • Las aplicaciones, la capa que realmente ve el usuario.

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:

  • onCreate, cuando la activity inicia, sólo se llama una vez. Método adecuado para crear la interficie de usuario.
  • onStart, indica que la activity va a mostrarse al usuario.
  • onResume, indica que el usuario ya puede interactuar con la activity. Método adecuado para iniciar sonidos o animaciones.
  • onPause, se inicia cuando la actividad está apunto de ir a un segundo plano. Aquí se debería guardar el estado interno actual de la aplicación.
  • onStop, cuando la actividad va a finalizarse (si el sistema tiene suficiente memoria puede no ser llamado nunca).
  • onRestart, cuando la actividad vuelve a un primer plano.
  • onDestroy, cuando la actividad va a eliminarse.
  • onSaveInstanceState y onRestoreInstanceState corresponden a métodos para guardar el estado de la interficie de usuario (lo que se está escribiendo en un cuadro de texto y tal), pero en las últimas versiones no es necesario debido a que ya lo hace el sistema por sí solo.

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:

  • Activities, es una pantalla de usuario.
  • Intents, son algo así como eventos, describen una acción (enviar un mail, hacer una llamada…). Por ejemplo el de enviar un mail, si la aplicación va a enviar un mail llamaría a este intent y el programa receptor arrancaría para enviar dicho mail; al contrario, por ejemplo, sería indicar ser el receptor de este intent, de esa forma cuando una aplicación fuese a enviar un mail avisaría a la tuya.
  • Servicios, programas que se están ejecutando siempre y en segundo plano. Por ejemplo el reproductor de música, se inicia como una Activity pero si cambias de aplicación pasa a ser un servicio que sigue reproduciendo la música.
  • Content Providers, son algo así como bibliotecas\librerías, que engloban código que se puede compartir entre aplicaciones.

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.

  • INTERNET: Acceso a internet.
  • READ_CONTACTS: Leer pero no escribir en los contactos del usuario.
  • WRITE_CONTACTS: Escribir pero no leer los contactos del usuario.
  • RECEIVE_SMS: Monitorear mensajes de texto que lleguen.
  • ACCESS_COARSE_LOCATION: Saber la localización simple (a partir de antenas o wifi).
  • ACCESS_FINE_LOCATION: Conocer la posición más concreta, a partir del GPS.

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:

  • FrameLayout: Coloca los hijos a partir de la posición top-left.
  • LinearLayout: Coloca los hijos en una columna o fila.
  • RelativeLayout: Coloca los hijos en relación a las características de otros o del padre.
  • TableLayout: Organiza los elementos en columnas-filas.

Los parámetros comunes para ellos:

  • xmlns:android="http://schemas.android.com/apk/res/android": Debería estar definida en la primera tag del XML, define el namespace del XML para Android.
  • android:layout_width=“” y android:layout_height=“”: Para indicar cómo se expandirá. Sus posibles valores son: fill_parent y wrap_content.

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…

  • ScrollView: Para entornos con scroll.
  • WebView: Si queremos que sea código html.

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

  • android:text: Es el texto que aparece en el control. En un control podemos indicar su valor a partir de los recursos. Por ejemplo si queremos acceder a un valor dentro del strings.xml pondremos como su valor algo así como @string/nombre_variable. Pero también podremos poner el texto directamente lo.
  • android:gravity: Es la posición de los elementos internos: center.
  • android:textColor: Color del texto.

Lista de controles

  • TextView: Corresponde a un texto simple (algo así como una label) dentro de la layout.
  • Button: Corresponde a un botón.
  • ImageButton: Botón con imágen. La imágen ha de estar en res/drawable-xxx y para indicar cual será la que se mostrará lo haremos a partir de la propiedad src, indicando @drawable/nombre-de-archivo-sin-extensión. Por ejemplo: android:src=“@drawable/state”.

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.

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

Métodos y propiedades de las Activity

  • Para finalizar una Activity llamaremos a su método finish().
  • Para iniciar una Activity necesitaremos utilizar un Intent.

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

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:

  • px: Píxels, puntos en la pantalla.
  • in: Inches.
  • mm: Milimetros.
  • pt: Points, 1/72 de una inch.
  • dp: Density-Independent Pixels. ¿?
  • dip, sinónimo de dp.
  • sp: Scale-independent pixels. Como los dp pero escalados según la fuente configurada por el usuario.

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

... Crear mensajes

  • android.widget.Toast

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();
  • android.app.AlertDialog

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

  • Theme.Dialog.

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:

  • CheckBoxPreference
  • EditTextPreference

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:

  • Log.(e): Errores.
  • Log.(w): Warnings.
  • Log.(i): Informacion.
  • Log.(d): Debuggin.
  • Log.(v): Verbose.

Como...

Minis

Notas

  • Podemos utilizar una clase anidada para recoger los eventos, pero por cada clase anidada que creemos gastaremos 1KB extra de memoria.
  • Para poder depurar un programa Android desde Eclipse, a parte de indicarlo al ejecutar (Debug As → Android Application), debemos añadir en AndroidManifest.xml la siguiente propiedad a la tag application: android:debuggable=“true”.
  • El SDK para Android viene con herramientas muy útiles para hacer un seguimiento de los threads de los procesos, controlar el emulador (hacer llamadas, enviar mensajes…), ver la memoria gastada, copiar y pegar ficheros en este…

El emulador

  • ctrl + f11 harán que el emulador cambie de horizontal a vertical.

En un dispositivo físico

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

  • El teléfono tiene que tener activada la depuración:
    1. Ajustes → Aplicaciones → Configuración → Permitir orígenes desconocidos
    2. Ajustes → Aplicaciones → Configuración → Desarrollo → Depuración USB

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

  • El comando ddms del directorio tools nos abrirá el monitor de debug de Alvik, con él podremos hacer capturas de pantalla.
fw/android.1272829163.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)