Android SDK

Ξ 5 comentarios

Cómo programar apps para Android #2: Ciclo de vida, vistas e interacciones

por Xabadu
Cómo programar apps para Android #2: Ciclo de vida, vistas e interacciones

Ya, ya, ya, ya.. Si sabemos que nos demoramos, pero es que nos habían escondido el teclado y nos demoramos meses en encontrarlo D:

Hoy continuamos con nuestra saga de Cómo programar Apps para Android desde cero, continuando desde donde dejamos en el número anterior y revisando específicamente 3 temas hoy: El ciclo de vida de una app, como trabajar con vistas y como interactuar con elementos en la pantalla.

El detalle, como siempre, después del salto.

 

 

Les recordamos que este tutorial forma parte de la saga Cómo programar apps para Android, el cual ya tiene una parte disponible, que pueden ver en este enlace:

 

 

Vamos con lo primero:

 

¿Qué necesitamos?

Específicamente, lo siguiente:

  • Un computador con el SDK de Android instalado (pueden ver la instalación en el link que dejamos arriba).
  • Un proyecto creado como el de la primera app que hicimos (que también pueden encontrar en el link que dejamos arriba).

 

¿Qué veremos hoy?

  1. Ciclo de vida de una app.
  2. Armar una vista para la app.
  3. Interactuar con elementos de una vista.

 

Sin más que decir, vamos, manos a la obra:

 

1.- Ciclo de vida de una app

Cuando hablamos de ciclos de vida en una app en Android, específicamente nos referimos a 2: El ciclo de vida de una app propiamente tal, y el ciclo de vida de cada una de las actividades que la componen. ¿En qué se diferencian? Lo veremos ahora:

Ciclo de vida de una app

Como vimos en el número anterior de esta saga, una app esta compuesta por 1 o más actividades (y que en este caso interactúan entre si) y realiza un “camino” desde el momento que la lanzamos hasta que la cerramos por completo.

Este camino se inicia luego de lanzar la app (abrirla desde el dispositivo). Es ahí donde automáticamente se va a la actividad que marcamos inicialmente como launcher (en el Manifest se puede encontrar en la lista de activities, marcada con un intent-filter). De ahí en adelante, el ciclo de vida de la app pasa a mano de las actividades que la componen, cada una de las cuales cuenta con un ciclo de vida propio, que veremos a continuación.

Ciclo de vida de una actividad

Cada actividad que compone una app tiene un ciclo de vida propio, desde el momento en que es llamada (ya sea al inicio o por otra actividad) hasta que es cerrada (parcial o completamente). El ciclo de vida esta compuesto por una serie de estados, que se pueden ver en este diagrama:

activity_lifecycle

El ciclo de vida está representado por una serie de métodos presentes en la clase Activity, los cuales pueden ser extendidos en nuestras propias actividades para agregar funcionalidades según necesitemos. Desde que una actividad se lanza hasta que se cierra o destruye, pasa por varios estados (con sus respectivos métodos), los cuales representan lo siguiente:

  • onCreate( ): Es el método inicial que se llama cuando la actividad recién se inicia, y el más común que veremos en todos los ejemplos, ya que siempre se extiende. Acá lo recomendado es hacer toda la configuración estática que vamos a necesitar, es decir: llamar vistas, enlazar objetos a las vistas, etc. Adicionalmente recibe como parámetro un Bundle que contiene el estado de la actividad previo a ser llamado, si existiese. Desde acá, la actividad siempre va hacia el método onStart( ).
  • onStart( ): Se llama a este método cuando la actividad se vuelve visible para el usuario. Desde aquí la actividad puede ir a dos métodos: onResume( ) si es que será completamente visible, o onStop( ) si es que queda oculta.
  • onResume( ): En este estado es cuando la actividad se encuentra completamente visible e interactuando con el usuario (independiente si estamos utilizando otros métodos). La actividad se mantiene siempre en este estado hasta que nos vamos a otra o cerramos la app, en ese momento se va a onPause( ).
  • onPause( ): Se llama a este método justo antes de que otra actividad vaya a pasar al frente de la app y volverse activa. Adicionalmente en este método se aprovechan de hacer algunas operaciones de sincronización de datos o detención de animaciones, por dar algunos ejemplos. Desde aquí pasa a onResume( ) si la actividad se vuelve a poner al frente, o a onStop( ) si queda oculta.
  • onStop( ): Es el método que se llama cuando la actividad ya no está visible de ninguna forma para el usuario. Desde aquí pasa a onRestart( ) si vuelve a ser visible, o a onDestroy( ) si ya no volverá a existir.
  • onRestart( ): Es un breve estado entre que la actividad ha sido detenida y vuelve a estar visible. Desde aquí pasa a onStart( ).
  • onDestroy( ): El estado final antes que la actividad sea destruida por completo y deje de existir.

En cada uno de estos métodos hay ciertas operaciones que se pueden (y acostumbran hacer) para ayudarnos con tareas específicas que requerirá nuestra aplicación. Iremos viendo más adelante en algunos ejemplos para ir entendiendo mejor este concepto.

2.- Armar una vista para la app

Si bien hemos dicho en varias ocasiones que una app es un conjunto de actividades que interactúan entre si, hay un concepto importantísimo que no debemos dejar de lado, que es el de las vistas, ya que como su nombre lo indica, es lo que vemos en la pantalla del dispositivo cada vez que interactuamos con la aplicación.

Concretamente, una vista es un archivo en formato XML que contiene código que representa elementos gráficos que se mostrarán en pantalla. Entre los elementos que se pueden colocar dentro de una vista, están:

  • Botón.
  • Checkbox.
  • Campos de texto (en distintos formatos).
  • Barras de progreso.
  • Listas de selección.
  • Textos.
  • Imágenes.
  • Tipos de layouts (más sobre esto luego).
  • Grillas.
  • Pestañas
  • Y más.

Hay una gran cantidad de elementos disponibles para utilizar en las vistas, lo que nos permite crear apps que son tremendamente usables y accesibles para quienes las descarguen y que la interacción sea lo más cómoda posible.

Las vistas o layouts son almacenados en el directorio res/layout de nuestros proyectos:

Captura de pantalla 2013-11-25 a la(s) 20.18.09

Si bien el archivo correspondiente a cada vista puede llevar el nombre que sea, es una buena práctica anteponer el activity_ antes del nombre para diferenciarla de otros tipos (que usaremos más adelante) y mantener un mejor orden en el proyecto.

Para agregar elementos a una vista, tenemos 2 opciones: Usar el editor visual que viene en el IDE que usemos (por lo general Eclipse o Android Studio), o bien agregar los elementos directamente desde el código, editando el archivo XML.

El editor visual se ve de esta manera:

visual_editor

Donde cada número es:

  1. Elementos gráficos: Acá hay un listado completo de elementos gráficos, separados por categoría, para agregar a las vistas. Si queremos usar alguno, solo debemos arrastrarlos hacia el área marcada con el número 2.
  2. Vista previa: Acá se ve una vista previa de la.. vista (?). Podemos ver una aproximación de como se verán los elementos en el dispositivo. Adicionalmente en la parte superior hay opciones que podemos ajustar como por ej: En que tipo de dispositivo emular, con que versión del SDK, que plantilla e incluso si mostrar en landscape (horizontal) o portrait (vertical).
  3. Outline: En este panel se muestran, organizadamente, todos los elementos que están agregados a la vista. Se anidan de acuerdo a si tienen relación padre-hijo (que ya veremos).
  4. Properties: Como su nombre lo indica, en este panel se pueden ver y editar las propiedades de un elemento gráfico, según lo seleccionemos en el panel Outline. (ya veremos los atributos)
  5. Graphic Layout: Es la pestaña que representa lo que vemos actualmente.
  6. Nombre de la vista.xml: Es la pestaña que tiene todo el código correspondiente a la vista (ahí podemos modificar directamente).

Tal como mencionábamos anteriormente, cada elemento que agreguemos a la vista tiene atributos, los cuales representan propiedades sobre como actuará el elemento visualmente. Si bien hay una gran cantidad de atributos, varios de los cuales son exclusivos para ciertos elementos, por lo mínimo siempre trabajaremos con 3:

  • id: El cual referencia a un elemento y debe ser único dentro de la vista, para que podamos enlazarlo desde una actividad.
  • width: Representa el ancho del elemento. Este parámetro recibe tanto valores numéricos (en pixeles o pixeles dinámicos, por lo general se recomienda lo segundo) o parámetros constantes definidos del sistema, como wrap_content (determina el ancho de acuerdo al contenido del elemento) match_parent/fill_parent (determina el ancho de acuerdo al elemento padre que lo contiene y lo llena)
  • height: Lo mismo que width, pero con respecto a la altura del elemento.

Ya veremos esto en mayor detalle un poco más adelante.

Si bien todos los elementos gráficos son opcionales para agregar a una vista, hay al menos uno que debe ir si o si cuando la estamos armando, que es un layout.

Layouts

Un layout es un elemento gráfico que ayuda a definir la estructura que tendrá la vista. A esta estructura posteriormente se pueden agregar otros elementos que ingresan anidados y tienen una relacion padre-hijo con el layout (como mencionábamos más arriba).

 Existen actualmente distintos tipos de layouts, los cuales se ocupan de acuerdo al tipo de estructura u organización que se necesitará en la vista. Entre ellos, y los más utilizados son estos dos:

  • Linear Layout: Que realiza una organización lineal de los elementos, apilándolos uno al lado del otro (o abajo del otro dependiendo de su orientación) y basándose en un atributo llamado weight para darles mayor o menor relevancia en la repartición de espacio. Tiene un atributo que indica la orientación bajo la cual se organizarán los elementos, que puede ser horizontal o vertical.
  • Relative Layout: En este tipo de layout, los elementos se posicionan de forma relativa de acuerdo a la ubicación de otros (a la derecha de X, abajo de Y, centrar en el padre, etc). Suena un poco complejo de entender al principio, pero viendo algunos ejemplos se irá entendiendo mejor. Por lo general este es el tipo de layout más cómodo para usar.

 

linearlayout

 

Ejemplo de Linear Layout

relativelayout

Ejemplo de Relative Layout

 

Además de estas dos, hay otras vistas que son utilizadas en diferentes instancias y que iremos viendo a través de ejemplos más adelante para entenderlas mejor. Entre estas podemos encontrar por ej: Gridview (que se utilizan para grillas o cuadrículas), Listview (que se utilizan para listados) y Webview (que se utilizan para representaciones de código Web).

Una vez que definimos el layout base que tendrá la vista, podemos ir agregando otros elementos dentro de el (como los mencionados más arriba), o incluso otros layouts para hacer una sub-organización.

3.- Interactuar con elementos de una vista

Una actividad y una vista están relacionadas mediante distintos procesos:

  1. Una actividad carga una vista y la muestra en pantalla.
  2. Una actividad enlaza objetos a elementos de la vista.
  3. Una actividad captura acciones realizadas sobre los elementos de la vista y realiza operaciones en base a ello.
  4. Una actividad despliega información de resultados en la vista.

 

Una actividad carga una vista y la muestra en pantalla

Este es el proceso más básico y se puede realizar múltiples veces dentro de una actividad (y en cualquier método propio además de onCreate). Tal como decíamos anteriormente, una actividad puede cargar distintas vistas durante su vida, como de la misma forma una vista puede ser cargada por distintas actividades sin problemas. Esto es muy útil si queremos reutilizar elementos y no hacer copias de la misma vista, que tendrían un alto costo de mantención en caso de hacer cambios.

Para cargar una vista, basta con solo hacer una llamada al método setContentView, pasándole como parámetro el identificador de la vista, de esta manera:

setContentView(R.layout.activity_main)

El parámetro que le pasamos al método es el identificador de la vista, o más bien una referencia hacia ese identificador, que está almacenado en el “famoso” R.java:

¿Qué es el R.java?

R es una clase que se genera automáticamente dentro de las apps que creemos, la cual contiene referencias a todos los recursos del sistema y a las áreas de memoria en donde se encuentran. Ahí encontraremos referencias a recursos como: vistas, elementos gráficos, cadenas de texto, etc.

Cada vez que queramos referenciar algún elemento, ya sea en el editor de vistas o en el código de las actividades, debemos referenciarlo a través de R.

Por ejemplo en el método anterior, como necesitamos un parámetro que referencie una vista, lo que estamos haciendo es obtenerla a través de R, diciéndole que en las vistas que tiene referenciadas, busque la de nombre activity_main (sin la extensión xml).

Eso hará que la vista se muestre en la pantalla del dispositivo.

Una actividad enlaza objetos a elementos de la vista

Este proceso es necesario para poder operar con los elementos visuales de la vista. Por operar nos referimos a poder capturar información que contienen, modificarla y presentar resultados en ellos de ser necesario.

Cada elemento gráfico que agregamos en una vista (botones, checkboxs, textos, imágenes, etc), tiene un objeto equivalente que podemos declarar en la actividad (con su respectiva clase y por ende atributos y métodos), el cual luego enlazamos a cierto elemento del mismo tipo con el método findViewById, pasándole como parámetro el id del elemento y podemos operar sobre él.

Por ejemplo, si en la vista agregamos un elemento del tipo TextView (texto), que tuviese un id texto1, lo enlazamos de esta manera:

TextView texto1 = (TextView) findViewById(R.id.texto1);

Revisando lo anterior podemos ver que declaramos un objeto de tipo TextView llamado texto1 (no es necesario que se llame igual al id del elemento en la vista) y luego le asignamos un valor casteado a tipo TextView y buscamos con el método findViewById el elemento en la vista activa que tiene ese id. Con esa llamada quedará capturado en el objeto y podemos llamar métodos de su clase para operar.

Una actividad captura acciones realizadas sobre los elementos de la vista y realiza operaciones en base a ello

Así como en otros lenguajes, para Android contamos con una funcionalidad muy útil para capturar acciones realizadas sobre los elementos, que son los listeners. Cuando definimos un listener en la actividad, le estamos diciendo a la app a que esté atenta si se realiza alguna acción interactiva con el elemento (un click o un tap por ejemplo) y que cuando eso suceda, ejecute ciertas acciones.

Esto es tremendamente útil para cuando solo queremos ejecutar ciertas funciones después de que pase algo, como por ejemplo si tuvieramos una pantalla de login en nuestra app y queremos que valide solo después de que el usuario presione el botón “Ingresar” por dar un ejemplo.

Estos listeners van asociados a cada elemento (están definidos en sus respectivas clases como métodos) y cada uno de ellos tiene ciertas particularidades que iremos viendo en ejemplos posteriomente.

Una actividad despliega información de resultados en la vista

Tal como capturamos elementos y la información que contienen, muchas clases de objetos tienen métodos que permiten cambiar estos datos (así como sus atributos). Por lo general cada clase cuenta con una serie de métodos que tienen el prefijo set (ej. setText, setColor, setVisibility). Iremos viendo casos a medida que presentemos ejemplos.

Continuando la app

Ahora que hemos visto un poco sobre vistas, layouts, elementos y como interactuar con ellos, vamos a aplicarlo en la app que empezamos a trabajar en el número anterior.

La última vez teníamos una actividad llamada MainActivity que tenía el siguiente código:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

Y una vista base llamada activity_main, la cual tiene 2 elementos agregados: Un layout (de tipo RelativeLayout) y un TextView que contiene el texto “Hello world!”, lo cual desde la perspectiva de código se ve así:

Captura de pantalla 2013-11-29 a la(s) 3.10.39

Ahora haremos unas leves modificaciones a ambos, partiendo por la vista, a la que le agregaremos un botón (arrastrándolo desde el editor visual a cualquier parte de la pantalla, o agregándolo por código), de manera que el código de la vista se vea así:

Captura de pantalla 2013-11-29 a la(s) 3.13.18

Y la vista se vea parecido a esto:

Captura de pantalla 2013-11-29 a la(s) 3.13.06

Si queda distinto no se preocupen, lo importante es la funcionalidad que añadiremos. Al botón le cambiamos algunos atributos como el texto (que sale con una advertencia en amarillo porque lo escribimos directamente en vez de asignarle un elemento de tipo cadena, ya veremos esto más adelante) y la posición, pero lo importante es que este presente, da lo mismo el mensaje y donde esté.

Y ahora que hemos agregado el botón, en la actividad haremos algunos cambios en el código para que se vea así (los cambios aparecen en los comentarios del código):

public class MainActivity extends Activity {

    /*
     * Declaramos objetos de tipo Button y TextView para capturar
     * los elementos */

     Button boton;
     TextView texto;

     @Override
     protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          /* Cargamos la vista */
          setContentView(R.layout.activity_main);

          /* Capturamos los elementos referenciando sus id's */

          boton = (Button) findViewById(R.id.button1);
          texto = (TextView) findViewById(R.id.textView1);

          /* Llamamos al método setOnClickListener de la clase Button,
           * el cual agregará un listener al objeto de manera que cuando sea presionado
           * (o clickeado), obtendrá el texto actual del objeto tipo TextView y se hará
           * una comparación: Si dice Hello World lo traducirá a español, de lo contrario
           * lo escribirá en inglés y se lo asignará al mismo objeto.
           *
           * El texto se obtiene con el método getText() y luego se llama de inmediato al
           * método toString() ya que lo que retorna getText() no es una cadena
           * y por ende no se puede comparar directamente.
           *
           * El método setOnClickListener recibe como parámetro un objeto de tipo
           * onClickListener y dentro se declara un método onClick que manejará las acciones
           * a realizar. Esta estructura es siempre la misma para este tipo de listeners. */

           boton.setOnClickListener(new OnClickListener() {
               public void onClick(View v) {
                   if(texto.getText().toString().equalsIgnoreCase("hello world!")) {
                       texto.setText("Hola mundo!");
                   } else {
                       texto.setText("Hello world!");
                   }

               }

           });
      }

      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          // Inflate the menu; this adds items to the action bar if it is present.
          getMenuInflater().inflate(R.menu.main, menu);
          return true;
      }

}

Y ahora si lanzamos la app en el emulador, veremos inicialmente esto:

Captura de pantalla 2013-11-29 a la(s) 3.50.24

 

Y al presionar el botón con el mouse, cambiará a esto:

 

Captura de pantalla 2013-11-29 a la(s) 3.50.34

 

Y podemos seguir probándolo cuantas veces sea, ya que el listener está preparado para manejar ambos casos sin problemas.

De la misma forma podemos ir probando otros métodos para hacer distintas modificaciones sobre el texto, o incluso sobre el mismo botón. Los instamos a hacer pruebas y experimentar de cara a lo que veremos en el próximo número.

Por ahora lo dejaremos hasta aca, y continuaremos viendo otros contenidos y más ejemplos en la próxima edición, en donde también reforzaremos algunos de los conceptos vistos aca.

Como siempre, si tienen alguna duda o comentario, los invitamos a dejarnos unas líneas a continuación para poder ayudarlos.

Y les recordamos que este tutorial ha sido desarrollado, probado y documentado por el equipo de CLH, por lo que cuenta con nuestro Sello de Garantía:

Sello de GarantÍa CLH

¡Hasta la próxima!

Comparte este tutorial

El culpable de todo esto

Las tardes gloriosas de domingo y las grandes ovaciones a estadio lleno, no son algo extraño para Xabadu. Luego de ser descubierto a los 4 años en un partido de barrio por los ojeadores del gran Aviación F.C., sacudió el mercado nacional al ser traspasado en $500 pesos chilenos (1 USD) y 3 coca colas al renombrado Estrella Blanca de Lolol. Luego de una impresionante carrera por equipos como Lozapenco, Santa Cruz, Deportivo Lago Chungará y una incursión en la 3a división del futbol de Kazajstan, su record imbatible hasta la fecha de 1257 goles en 20 partidos lo llevo a ser elegido como uno de los arqueros más recordados en la historia pelotera nacional. Una lesión en el colmillo superior derecho lo llevó al retiro el año 2003, pero está de vuelta y sin duda que su jerarquía y experiencia internacional será un gran aporte.

En los barrios marginales se le conoce como: Xabadu

Comentarios en Facebook

5 Comentarios

  • Hola! Muy bueno está! Pero tarda mucho en publicar la saga :/ a este paso voy a programar en el 2016 algo completo xD
    Saludos!

  • Wow, estoy aprendiendo!! porfa apuren la parte III 😀

  • tenes un simple error en el codigo, que me trabo bastante, cuando creas la clase dentro del metodo setOnClickListener()

    debe ser asi: new View.OnClickListener(){… }
    falta el View.

    • Jorge,

      Si te apareció ese error es que importaste la clase errónea que contenía el método. Cuando Eclipse te marca error en setOnClickListener, debes importar la versión de la clase View y así no es necesario adjuntar el prefijo que indicas. De todas maneras las dos maneras sirven.

      Saludos!

  • […] Cómo programar apps para Android #2: Ciclo de vida, vistas e interacciones […]

Responder a Cómo programar apps para Android #3: Navegando entre actividades y preferencias de la app - Como Lo Hago Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Gente linda que nos quiere

Donde mas estamos