Primeros pasos en Android.

5
36672

Primeros pasos en Android

0. Índice de contenidos.


1. Introducción

En este tutorial vamos a crear una aplicación de ejemplo en Android y analizaremos sus elementos iniciales. Vamos a aprender como comunicar actividades, y vamos a dar algunos consejos de diseño de aplicaciones, en resumen, un tutorial para iniciarnos en el mundo Android. Si no sabes como montar el entorno de desarrollo, en este tutorial puedes ver como hacerlo.


2. Entorno

  • Hardware: Portátil MacBook Pro 15′ (2.0 GHz Intel i7, 8GB DDR3 SDRAM, 500GB HDD).
  • AMD Radeon HD 6490M 256 MB
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.7
  • Software: Eclipse Helios


3. Entendiendo los elementos básicos de una aplicación Android

Lo primero de todo es crearnos una aplicación de prueba, así que pinchamos en File > New > Other > Android > New Android Project, tal y como muestra la imagen:

Una vez hecho esto tenemos un proyecto básico con los elementos que describo a continuación.


3.1 AndroidManifest.xml

  
  
      
  
      
          
              
                  
                  
              
          
          
      

  • En la línea 3 vemos como se está declarando el paquete en el que por defecto se buscarán las actividades que declaremos en nuestra aplicación.
  • Las líneas 4 y 5 entran más en juego cuando queremos poner nuestra aplicación en el Market, ahora conocido como Play Store. Básicamente es para indicar el número de versión de nuestra aplicación y es importante ya que el Play Store detectará cambios de versión cuando cambiemos estos números
    y avisará a nuestros usuarios de que hay una actualización disponible.
  • La línea 6 indica el número de versión mínima del API necesario para que corra nuestra aplicación. Play Store filtra las búsquedas de aplicaciones por este número de tal forma que un dispositivo que tenga un número de versión inferior al requerido no podrá instalar la aplicación.
  • En la línea 8 nos encontramos con @drawable/icon. Esta es la forma de seleccionar el icono de nuestra aplicación. Si os fijáis dentro de res, tenemos 3 carpetas drawable para 3 tipos de pantalla distintas en función del dispositivo (alta calidad, calidad media y calidad baja). También tenemos
    @string/app_name, que es como se accede a los literales en Android. Esto lo que hace es buscar la cadena «app_name» en el archivo strings.xml, y en este caso se lo asigna como título de nuestra aplicación.
  • En la línea 9 tenemos declarada la actividad, que si os fijáis la está buscando en la concatenación del package definido en la línea 3 y del android:name que tenemos definido en esta línea.
  • En la línea 11 tenemos definido un intent-filter. En este caso action tiene como valor android.intent.action.MAIN.Esto indica al sistema, que es la actividad principal de nuestra aplicación. Se inicia sin parámetros. Es una buena idea poner solamente una actividad principal en el manifest. En
    cuanto a category la creación del proyecto lo ha seteado al valor android.intent.category.LAUNCHER. Esto le dice al sistema que la actividad que la
    contiene debe ser lanzada cuando el icono de la aplicación del teléfono es pulsado. Además le dice a Android que el icono de nuestra aplicación debe aparecer en la zona de las aplicaciones que se pueden ejecutar.

Sobre la clase Intent vamos a hablar más tarde así que por ahora no entro en más detalle.


3.2 strings.xml

  
  
    Hello World, FirstActivity!  
    SampleProject1  
  

Cuando añades una cadena de texto al fichero strings.xml le estas diciendo a Android que el texto puede ser accesible por el android resource
manager
mediante el nombre que le des. Podemos ver como tenemos registrados los literales de la aplicación. Títulos, textos, identificadores de vista …No necesita mucha más explicación.


3.3 R.java

/* AUTO-GENERATED FILE.  DO NOT MODIFY. 
 * 
 * This class was automatically generated by the 
 * aapt tool from the resource data it found.  It 
 * should not be modified by hand. 
 */  
  
package com.autentia.android;  
  
public final class R {  
    public static final class attr {  
    }  
    public static final class drawable {  
        public static final int icon=0x7f020000;  
    }  
    public static final class layout {  
        public static final int main=0x7f030000;  
    }  
    public static final class string {  
        public static final int app_name=0x7f040001;  
        public static final int hello=0x7f040000;  
    }  
}

Esta clase es autogenerada por Android, y sirve para poder acceder a distintos parámetros desde las clases Java. Como bien dice el comentario, no debe
editarse a mano.


3.4 FirstActivity.java

package com.autentia.android;  
  
import android.app.Activity;  
import android.content.Context;  
import android.os.Bundle;  
  
public class FirstActivity extends Activity {  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
    }  
}

Es la clase que nos crea Android por defecto si así se lo indicamos. Esta clase se crea de la siguiente forma:

El único método que se sobreescribe de la clase padre es onCreate. Si os fijáis lo primero que hacemos es llamar al onCreate de la clase Activity. Esto se hace así porque cuando una actividad se crea, se puede querer crear con información que tenía previamente. Esta información se recibe en el objeto savedInstanceState. Imaginaos por ejemplo que cambiamos la posición del móvil a apaisado mientras rellenamos un formulario. Este cambio provoca que la actividad se creé de nuevo, y lo más usable, es que los campos que ya haya rellenado el usuario sigan rellenos con la misma información. Ya veremos luego como conseguir esto.

También vemos que se está llamando al método setContentView. Este método solo se puede llamar desde onCreate, y además es un campo immutable. Solo se puede fijar la vista de la actividad una sola vez. Es la forma que tiene Android de obligarnos a tener una única vista por actividad.


4. Actividades en Android

Para los que estéis familiarizados con el modelo MVC (Model-View-Controller), una actividad es lo análogo a un controlador. Es una buena práctica tener
una actividad por cada pantalla de nuestra aplicación. Toda actividad debe heredar de la clase Activity, y debería, aunque no es obligatorio implementar el método onCreate.


4.1 Entendiendo el ciclo de vida de una actividad

Las actividades tienen un ciclo de vida frenético. Continuamente se crean y destruyen nuevas actividades, por lo que es fundamental conocer el ciclo de vida de estas para poder salvar información importante antes de que se destruyan y para inicializarlas antes de que
se le muestren al usuario. Todo este baile comienza cuando se hace un broadcast al sistema de un intent, que está registrado en nuestra actividad para que esta lo reciba.

En ese momento el sistema llama al constructor de la actividad mientras que también inicia la aplicacion si es necesario y llama a los siguientes métodos por orden:

  • onCreate

  • onStart

  • onResume

Se supone que al implementar una actividad debemos extender estos métodos que conforman el ciclo de vida. Cuando un usuario pulsa el boton de retorno desde la actividad, estos métodos son llamados por este orden:

  • onPause

  • onStop

  • onDestroy

Ejemplos de acciones que destruirán una actividad:

  • Cambio del movil a apaisado o viecversa
  • La actividad ya no se ve en la pantalla, o el sistema esta bajo de recursos
  • Es martes
  • El usuario preciona el boton de retroceso o de Home y sale de la aplicacion

Después de estas acciones la actividad es cerrada y debería estar lista para el garbage collector.

Vamos a ver los métodos del ciclo de vida en detalle. Recuerda que se debería invocar al método de la super clase ( a menudo antes de hacer nada ) o Android nos tirará excepciones.


4.1.1 onCreate

Como hemos dicho antes, es el primer método que se llama cuando se crea una actividad, y es el lugar donde llamar a setContentView. Como ya te habrás podido imaginar, no es un buen sitio para poner cosas que vayan a cambiar cuando la aplicación
esté dormida.


4.1.2 onStart

Se llama immediatamente después del onCreate. Si nuestra aplicación estaba en segundo plano, onStart será llamado cuando la aplicación vuelva a estar en primer plano.


4.1.3 onResume

Es el último método que se llama antes de que la actividad tenga acceso a la pantalla. Si algún elemento del interfaz gráfico ha cambiado mientras la actividad estaba en segundo plano este método es el sitio para asegurar que el estado está sincronizado. No importa de que estado venga, cuando la actividad vuelva a estar en primer plano este método será llamado.


4.1.4 onPause

onPause: es el primer método que se llama cuando la aplicación se está yendo de la pantalla. Si tenemos bucles, procesos, animaciones que deberían estar corriendo
cuando la actividad está en pantalla este método es el idóneo para pararlos. Este método también se llama cuando lanzamos otra actividad desde la que se está ejecutando
actualmente. Este método es importante porque puede ser el único en avisarnos de que la actividad o incluso toda la aplicación se está cerrando. En este método
deberíamos guardar cualquier información importante a disco, base de datos o preferencias.


4.1.5 onStop

Cuando se llama a onStop lo que sabemos es que la actividad está oficialmente fuera de pantalla.
No siginifica que la actividad se esté apagando, aunque podría ser. Solo se puede asumir que el usuario ha dejado tu actividad por otra. Si estás haciendo algún proceso
que solo debería estar corriendo cuando la actividad está en ejecución este es un buen momento para pararla.


4.1.6 onDestroy

Es el último método que se llama antes del final. Es la última oportunidad para limpiar lo necesario antes de que el garbage collector la elimine por completo.
Cualquier proceso de background que la actividad puede taner corriendo debe pararse. Sin embargo porque este método se haya llamado no significa que la actividad sea
borrada. Si tienes algún hilo corriendo, este puede seguir corriendo y consumiendo recursos incluso aunque este método se llame.


4.2 Formas de retener los datos

Nuestro proceso puede ser destruido en cualquier punto después de que onPause se ejecute, si el sistema necesita recursos. El usuario, sin embargo, nunca debe enterarse de esto. Para conseguir este efecto,
Android te da 2 oportunidades de salvar el estado para su uso posterior.

1ª onSaveInstanceState:

Este método te pasa un objeto donde se puede poner cualquier dato que se necesite para restaurar la actividad a su último estado. Algunas veces esto se consigue llamando a outState.putString o outState.putBoolean. Cualquier valor almacenado requiere una clave para almacenarse y la misma para sacarse. Tú eres el responsable de sobreescribir tu propio onSaveInstanceState. Este método no se va a llamar si el usuario presiona la tecla de retorno. onSaveInstanceState solo se llama cuando el sistema considera que podemos querer
recuperar el estado posteriormente, por lo tanto no es un buen sitio para salvar datos del usuario, solo datos a nivel de interfaz gráfico importantes en esta instancia de la pantalla. En FirstActivity.java, si os fijáis, se le pasa un objeto de tipo Bundle, que es
precisamente este objeto que estamos comentando, y vale para lo que os comenté antes. Si hemos cambiado la pantalla de posición, la actividad se va a crear de nuevo y no queremos volver a pedir al usuario información que haya introducido previamente, con lo que con este objeto
podemos rellenar los campos que ya había rellenado o selecionar lo que quiera que el usuario hubiera seleccionado.

2ª onRetainConfigurationStance

Cuando se destruye una actividad y se crea de nuevo por un cambio en la configuración, como el anteriormente mencionado ejemplo de pasar el móvil a apaisado , es cuando se llama este método. Para obtener cualquier objeto guardado previamente se ha de llamar a getLastNonConfigurationInstance. Llamando a este método conseguimos que las transiciones de rotación de pantalla sean más rápidas.


5. La clase Intent

La clase Intent conforma el protocolo de comunicaciones de Android para mover información entre componentes de aplicaciones. En una aplicación Android bien diseñada sus
componentes no deberían acceder directamente a las instancias de otros componentes. Para eso están los intents. Hay 2 formas de decir al sistema Android
que te gustaría recibir intents enviados por el sistema, por otras aplicaciones o incluso por tu propia aplicación:

  • 1. Registrando un <intent-filter> en el manifest
  • 2. Registrando un IntentFilter en tiempo de ejecución.

Si deseamos que nuestro código esté a la espera de un aviso, o haga una acción basada en un evento deberíamos declarar el intent a nivel de manifest y no en tiempo
de ejecución, ya que puede que nuestra aplicación no se esté ejcutando en ese momento. Si solo debe recibir el intent cuando la aplicación está corriendo
entonces podemos registrar un IntentFilter, tanto en el manifest como en código Java.


5.1 Intent en Runtime. Ejemplo 1.

Vamos a empezar creando un ejemplo para ver como se crearía un IntentFilter en tiempo de ejecución (runtime), y así dejamos un poco la teoría, que siempre es más aburrida. El ejemplo va a ser el siguiente:

  • Crear una actividad que vamos a llamar SecondActivity.java
  • Crearnos una pantalla para esta actividad, que simplemente muestre el mensaje: «Bienvenido a la segunda Actividad !»
  • Hacer que cuando se pulse el botón «Menú» del terminal, se haga una transición desde FirstActivity a SecondActivity

Empezamos creándonos una clase Java con el nombre SecondActivity.java, en el paquete com.autentia.android. Esta clase es una Actividad, asique tenemos que extender de Activity. Además como va a tener asociada una pantalla mostrando un mensaje estático
aprovechamos para setearle dicha pantalla. La clase nos debería quedar de la siguiente forma:

package com.autentia.android;  
  
import android.app.Activity;  
import android.os.Bundle;  
  
public class SecondActivity extends Activity{  
  
    @Override  
    public void onCreate(Bundle icicle) {  
        super.onCreate(icicle);  
        setContentView(R.layout.second_activity);  
    }  
}

En la línea 11, estamos seteando la vista a second_activity, así que vamos a crear la vista. Nos vamos a la carpeta layout, que está dentro de res, y pinchamos con el botón derecho sobre la carpeta, y hacemos click en New > Other > Android XML File

En el nombre introducimos second_activity y pulsamos en Finish.

Antes de seguir, nos vamos al fichero strings.xml y añadimos la siguiente línea: <string name=»second_activity_text»>Bienvenido a la segunda Actividad !</string>

Ahora volvemos al layout que nos acabamos de crear (second_activity.xml) y lo editamos para añadir este String. Nos debería de quedar algo parecido a lo siguiente:

  
  
      
      
      
  
 

En la línea 7 es donde estamos pintando en la vista de esta actividad el mensaje que hemos declarado en strings.xml.

Ahora lo que nos queda es simplemente hacer que desde FirstActivity.java cuando se pulse el botón «Menú» se muestra la pantalla que acabamos de crear. Vamos a hacer declarando un Intent a nivel de runtime.

En Android hay un método que se llama onKeyDown, que se ejecuta cuando pulsamos una tecla estando en la pantalla de una actividad. Vamos a redefinirlo para que quede de la siguiente forma:

@Override  
public boolean onKeyDown(int keyCode, KeyEvent event) {  
      
    if ( keyCode == KeyEvent.KEYCODE_MENU ) {  
        Intent startIntent = new Intent(this.getApplicationContext(), SecondActivity.class);  
        startActivity(startIntent);  
        return true;  
    }     
    return super.onKeyDown(keyCode, event);  
} 

Este método se va a llamar cuando se pulse cualquier tecla, así que lo primero que tenemos que hacer es comprobar que tecla se ha pulsado. Si es la de menú, entonces lo que hacemos en la línea 5 es crear un intent, en el que seteamos el contexto actual e indicamos a que clase vamos a pasárselo. En la línea 6 indicamos que
se pase a ejecutar la actividad SecondActivity, y devolvemos true. Devolvemos true para indicar que hemos tratado con éxito la casuística de onKeyDown. En caso de no cumplirse el if, lo que hacemos es llamar al método del padre, para que trate él la tecla pulsada.


5.1 Intent en Runtime. Ejemplo 2.

Ya hemos visto en el ejemplo 1, como se pueden comunicar las actividades entre ellas, y ahora vamos a hacer otro ejemplo para ver como una actividad propia del dispositivo puede desencadenar ciertas acciones en nuestra aplicación. El ejemplo va a ser el siguiente:

Cuando el usuario se sube a un avión pone el teléfono en modo avión para quitar cobertura y datos. Vamos a registrar esta acción del usuario para mostrar un mensaje flotante en pantalla si la aplicación esta visible, para avisar al usuario de que es necesario tener internet para que la aplicación funcione correctamente.

Vamos a la clase FirstActivity.java y añadimos el siguiente código:

public class FirstActivity extends Activity {  
      
    private BroadcastReceiver simpleReceiver = new BroadcastReceiver() {  
          
        @Override  
        public void onReceive(Context context, Intent intent) {  
              
            if ( intent.getAction().equals(Intent.ACTION_AIRPLANE_MODE_CHANGED) ) {  
                Toast.makeText(context, R.string.airplane_change, Toast.LENGTH_LONG).show();  
            }  
        }  
    };  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        final IntentFilter intentFilter = new IntentFilter();  
        intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);  
        registerReceiver(simpleReceiver, intentFilter);  
    }  
    @Override  
    public void onPause() {  
        super.onPause();  
        try {  
            unregisterReceiver(simpleReceiver);  
        } catch ( Exception exception ) {  
              
        }  
    }  
}  
  • En la línea 3 declaramos un BroadCastReceiver, reimplementando onReceive. Aquí es importante que se compruebe el tipo de Intent que nos llega. En este ejemplo ya veremos ahora que no, pero podría ser que un BroadCastReceiver estuviera preparado para realizar varios tipos de acciones en función del Intent,
    luego es una buena práctica preguntar de que tipo es, y aplicar la acción correspondiente.
  • En la línea 8 comprobamos que el intent que recibimos se correponde con el paso a modo avión, y no con el de batería baja por ejemplo.
  • En la línea 9 estamos utilizando la clase Toast que nos sirve para sacar notificaciones al usuario que desaparecen en un breve periodo de tiempo
    por si mismas. Obsérvese que el mensaje R.string.arisplane_change lo tenemos que crear en el archivo strings.xml de forma análoga a como lo hicimos antes, con el mensaje que deseemos, y es importante, como siempre que utilizamos las notificaciones de la clase Toast, que el mensaje sea corto, consico y claro.
  • En las líneas 18 y 19 creamos un IntentFilter y le asignamos la acción de cambio a modo avión. Como dije antes podíamos asignarle más, y hacer otras acciones según nos llega un tipo de Intent u otro.
  • En la línea 20 llamamos a la función registerReceiver, que sirve para registrar en el BroadCastReceiver todas las acciones que hayamos añadido a nuestro IntentFilter.
  • En la línea 26 lo que hacemos es quitar el BroadCastReceiver, ya que si nuestra aplicación está pasando a segundo plano, no nos interesa mostrar al usuario que necesita internet para que funcione nuestra aplicación, porque ya no la está viendo. El try es importante porque el método unregisterReceiver lanza excepciones que colapsan la aplicación, cuando el BroadCastReceiver ya ha sido desligado, o cuando no está ligado. Esto es un workaround, lo ideal sería comprobar algún tipo de flag, que indicara si lo tiene ligado o no y actuar en consecuencia. Dejo al lector la tarea de investigación de este asunto ;).

Un consejo final de regalo

A medida que las aplicaciones van creciendo, es posible que al instalarla en vuestro terminal para probarla os de un error de Timeout y no se os ejecute la aplicación. Esto pasa por tener el tiempo de conexión por defecto a 5 segundos. Lo podéis aumentar como se muestra en la siguiente imagen para solventar el fallo. Tendréis que aumentar el valor de ABD connection time out (ms).


6. Conclusiones

Entender el ciclo de vida de las actividades en Android me parece básico para poder hacer un desarrollo correcto, y es por este motivo por el que he querido incluirlo en este tutorial. A día de hoy una aplicación con su homóloga en dispositivos móviles, es una aplicación con una ventaja competitiva frente a otra que solo se pueda utilizarse desde un ordenador, ya que a menudo no disponemos de él. Espero que os haya sido de utilidad el tutorial. Un saludo !!


7. Información sobre el autor

Alberto Barranco Ramón es Ingeniero Técnico en Informática de Gestión y Graduado en Ingeniería del Software por la Universidad Politécnica de Madrid

Mail: abarranco@autentia.com.

Twitter: @barrancoalberto

Autentia Real Business Solutions S.L. – «Soporte a Desarrollo».

Alberto Barranco Ramón
Consultor tecnológico de desarrollo de proyectos informáticos.
Ingeniero técnico en informática de gestión y graduado en ingeniería del software por la Universidad Politécnica de Madrid.
Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.
Somos expertos en Java/Java EE

5 COMENTARIOS

  1. Tengo un inconveniente en el ejemplo 5.1. Cuando le doy clic al boton de \\\»menú\\\» en la máquina virtual me aparece el siguiente mensaje: \\\»The application SampleProject (process com.autentia.android) has stopped unexpectedly. Please try again.\\\»

  2. Encontré el problema… cuando compile el programa paso a paso, me decía que me faltaba algo en el archivo AndroidManifest.xml y era la siguiente línea de código:

  3. Realizando el ejemplo 5.2 encuentro el siguiente inconveniente… Al pasar al código que se menciona, hay 3 variables que no estan definidas y toca definir… airplane_change y main. La primera si es sencillo, como bien se menciona, es agregar una línea al strings.xml Cambiando a modo de avión pero main es de tipo layout… el compilador me sugiere lo siguiente: \\\»Create field \\\’main\\\’ in type \\\’layout\\\’\\\» y cuando lo hago entra a modificar el R.java, lo cual ese archivo no me lo permite modificar… porfavor, ayudame en esto, gracias.

  4. Ya encontre el error… como es un layout, es un archivo xml donde se define la apariencia gráfica de una actividad… lo que tocaba hacer era definir en la carpeta layout main.xml siendo esta, la primera pantalla al iniciar la aplicación… debes tener cuenta que si este post son los primeros pasos en android, debes aclarar y definir como es el trabajo que hace el compilador los componentes principales de un proyecto en Android. Gracias.

  5. a ver >:c es urgente que por favor en 3.1, en la descripcion de la linea 8 en lugar de «alta calidad» pongan «calidad alta» por cuestiones de mi trastorno obsesivo compulsivo, para que en los 3 tipos de calidad, la calidad se encuentre antes de «alta, media, baja». Gracias por su atencion >:c

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad