ASánchezDíaz

Autoaprendiendo .NET y otras cosas


Comunicación entre Activities con Intents

Uno de los aspectos más importantes y que tendremos que manejar con frecuencia en la programación de aplicaciones Android es la comunicación entre las activities que las componen.

A menudo, nos bastará con pasar variables sencillas, como una cadena de texto o un número, pero otras veces necesitaremos proporcionar a la nueva Activity información algo más compleja, como un objeto o una lista de objetos.

El ejemplo más simple que se me ocurre es el de una activity que recoja el nombre del usuario y lo envíe a otra activity que le de la bienvenida. Lo que hay que hacer a grandes rasgos es llamar a la segunda activity desde la primera. Esto lo hacemos con un Intent.

Vamos a poner un ejemplo.

Creamos un nuevo proyecto con Android Studio y lo llamaremos ComunicacionJson. Para ello, desde la ventana principal seleccionamos “Start a new Android Studio project” o, si ya tenemos un proyecto abierto, desde “File -> New -> New project”.

¿Por qué eso de Json? Hablaremos más adelante de JSON, aunque nada en esta entrada. He elegido este nombre porque pretendo usar este proyecto para entradas posteriores.

Ventana inicial de Android Studio

Asignamos un nombre al proyecto, en nuestro caso “ComunicacionJson”, aunque lógicamente es válido cualquier otro nombre.

Asignando nombre al proyecto

Para este proyecto, he elegido el tipo de Activity “Empty”

Seleccionar tipo de Activity

Ahora asignamos un nombre a la activity principal. Yo he elegido “MainActivity”

Asignando nombre a la Activity

Pulsamos el botón “Finish” y esperamos a que el proyecto se cargue.

Este es el código que genera Android Studio para MainActivity.java:

package com.asanchezdiaz.comunicacionjson;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

Para mejor compatibilidad entre versiones, Android Studio extiende MainActivity de AppCompatActivity, aunque podríamos hacerla extender de Activity, lo dejaremos así.

El código de MainActivity tiene poco de especial. Además del nombre del paquete (package) y los imports, sólo contiene el método onCreate. Aunque no he hablado de la estructura y el ciclo de vida de una Activity, este método se llama siempre en primer lugar cuando Android crea la Activity, por lo que es un buen sitio para hacer varias cosas.

El método onCreate, recibe el argumento Bundle savedIntanceState, del que tampoco hemos hablado, pero básicamente sirve para “restaurar” el estado de la Activity en caso de que Android “se la haya cargado”. Android cerrará y finalizará Activities que se encuentran en segundo plano si considera que necesita los recursos que están ocupando, de forma que la información del estado que tenía la Activity se puede recuperar y establecer. De esto hablaremos más adelante.

El método onCreate se hereda de Activity. Aquí lo estamos “sobreescribiendo” (@Override). La línea super.onCreate(savedInstanceState); hace una llamada al método de la clase superior.

Cómo ya he dicho, de todo esto hablaremos más adelante.

Por último, la línea setContentView(R.layout.activity_main); asigna el layout (xml que define la interfaz) de esta activity. Este archivo, activity_main.xml, lo ha generado Android Studio al crear MainActivity y se encuentra en el directorio app/src/main/res/layout. Aquí se guardan los archivos xml de interfaz.

En la parte izquierda de la ventana de Android Studio, podemos acceder a la pestaña “1:Project”, que en función de la vista seleccionada tendrá una estructura de directorios o paquetes. En mi caso, he seleccionado Android que para mí es más cómodo:

Pestaña Project

Ahora abriremos (si es que no se ha abierto automáticamente) el archivo activity_main.xml. Vamos a añadir algunos controles:

  • Un control TextView, que informará al usuario de las intrucciones
  • Un control EditText, donde el usuario introducirá su nombre
  • Un control Button, que abrirá una nueva Activity que será la encargada de mostrar el nombre

Además de esto, haremos algunos cambios. Modificaremos el tipo de Layout: en lugar de RelativeLayout usaremos un LineraLayout. Tanto RelativeLayout como LinearLayout son dos de las múltiples formas de ordenar los controles en la interfaz, son “contenedores de controles”. LinearLayout en este caso, necesita un parámetro adicional: orientation, que indica si los controles se deben ordenar horizontal o verticalmente. También eliminaremos el TextView por defecto que incluye Android Studio con el texto “Hello World!”. Una vez hechos estos cambios, éste es el código de activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.asanchezdiaz.comunicacionjson.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Introduce tu nombre para verlo en la siguiente activity" />

    <EditText
        android:hint="Introduce tu nombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:text="Mostrar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

En la pestaña Preview, normalmente a la izquierda, podemos ver el resultado:

Vista previa

No hay mucho que decir, LinearLayout ha ordenado los controles verticalmente, como le hemos dicho mediante el android:orientation=”vertical”. Los parámetros android:layout_width y android:layout_height establecen el ancho y alto respectivamente de cada control. En este caso su valor es “wrap_content“, que asigna el espacio necesario. Otros valores pueden ser “match_parent” (que hace coincidir el ancho o el alto con el del contenedor, padre o parent del control, en este caso LinearLayout) o un valor (por ejemplo “200dp”). Una valor en desuso es “fill_parent” que rellena el contenedor con el control, aunque casi nunca es práctico y está siendo eliminado (se marcó como “deprecated” en la API 8, al escribir esta entrada vamos por la API 24).

Los tres controles tienen establecido el texto con android:text al que se le ha asignado una cadena de texto por control. Android Studio no va a dar errores, pero se va a quejar de esto, ya que es mejor usar archivos de recursos para establecer los textos. Esto es bueno por ejemplo, para facilitar las traducciones. de esto también hablaremos.

El parámetro android:hint del EditText lo hemos usado para mostrar un texto explicativo en el control, que desaparecerá siempre que el usuario haya introducido texto y volverá a aparecer siempre que el control está vacío de nuevo.

Llegados a este punto, faltan algunas cosas importantes, por ejemplo, el botón no tiene ni idea de lo que tiene que hacer. Debemos decírselo. Tenemos dos formas de hacer esto, desde el xml o desde el código de MainActivity. En esta entrada usaremos la primera opción y lo haremos con el parámetro onClick:

    <Button
        android:text="Mostrar"
        android:onClick="mostrarNombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

El método mostrarNombre es el que se ejecutará cada vez que el usuario pulse el botón, pero aún debemos crear el método, lo haremos en MainActivity.java, incluyendo el código:

    public void mostrarNombre(View view) {
    }

tras el método onCreate(..). Más adelante implementaremos el método.

Otra cosa importante, es: ¿cómo tendremos acceso al nombre que haya introducido el usuario? Bueno, debemos identificar al EditText:

    <EditText
        android:id="@+id/txtNombre"
        android:hint="Introduce tu nombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

Lo hemos hecho con el parámetro: android:id=”@+id/txtNombre”, a partir de ahora el identificador del EditText es “txtNombre” y desde MainActivity tendremos que llamarlo por su “nombre” o “id”. Este identificador debe ser único por cada layout.

Por tanto, el código final de activity_main.xml es:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.asanchezdiaz.comunicacionjson.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Introduce tu nombre para verlo en la siguiente activity" />

    <EditText
        android:id="@+id/txtNombre"
        android:hint="Introduce tu nombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:text="Mostrar"
        android:onClick="mostrarNombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Vamos ahora a crear la Activity que se abrirá para mostrar el nombre que introduzca el usuario. La mejor manera de hacerlo es, desde la pestaña 1:Project, haciendo click con el botón secundario del mouse en el package en el que queremos añadir la Activity, en este caso com.asanchezdiaz.comunicacionjson y elegir New -> Activity -> Empty Activity.

Añadiendo una nueva Activity

De esta forma Android Studio generará todo lo necesario, el archivo layout, el archivo java, registrará la Activity en AndroidManifest.xml, etc… Desde este punto, crear la nueva Activity es análogo a cuando creamos MainActivity, es decir, elegiremos un nombre y Android Studio hará lo demás.

Yo he elegido el nombre “VerNombreActivity” y ya tengo creado tabién el archivo layout: activity_ver_nombre.xml.

En este archivo, de igual forma a cómo lo hicimos con activity_main.xml, incluiremos algunas modificaciones. Añadiremos un control TextView. El archivo activity_ver_nombre quedará de la siguiente forma:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.asanchezdiaz.comunicacionjson.VerNombreActivity">

    <TextView
        android:id="@+id/lblNombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

En este caso, no hemos especificado la orientación en LinearLayout (sólo hay un control) y hemos asignado un identificador “lblNombre” al TextView. Lo necesitamos para acceder a él.

Ya tenemos todo montado. Manos a la obra.

Nos centraremos ahora de nuevo en MainActivity.java, en concreto en el método mostrarNombre que creamos antes que quedará:

    public void mostrarNombre(View view) {
        //Buscamos el control EditText por su id en el layout activity_main.xml
        EditText txtNombre = (EditText)findViewById(R.id.txtNombre);
        
        //Leemos el nombre del usuario y lo guadamos
        String nombre = txtNombre.getText().toString();
        
        //Crearemos un Intent en el que almacenaremos el nombre del usuario
        //y que usaremos para iniciar la nueva Activity
        
        //Asociamos las dos Activities
        Intent intent = new Intent(this, VerNombreActivity.class);
        
        //Almacenamos el nombre en el Intent
        intent.putExtra("nombre", nombre);
        
        //Iniciamos la Activity usando el Intent, que ya lleva el nombre
        startActivity(intent);
    }

Podemos ver la forma de “encontrar” nuestro control con el método findViewById(R.id.txtNombre) (R es algo así como un índice de recursos autogenerado). Leemos el nombre y lo almacenamos en un Intent que asocia las dos activities. Luego iniciamos la segunda Activity.

En la línea intent.putExtra(“nombre”, nombre); hemos almacenado el nombre bajo el indicador “nombre”… podríamos haber elegido cualquier otro indicador: intent.putExtra(“name”, nombre); por ejemplo.

Por supuesto, este código es muy básico. Lo ideal es hacer algunas comprobaciones, por ejemplo, si el control es nulo o si el usuario ha introducido algún valor… pero por claridad lo dejaremos así y confiaremos en el usuario (que no se debe hacer nunca 😉 )

Vamos ahora a la segunda Activity. Debemos implementar la forma de obtener el nombre. Lo haremos creando un método al que llamaremos “mostrarNombreUsuario()”:

    private void mostrarNombreUsuario() {
        //Obtener el Intent que hemos recibido
        Intent intent = getIntent();

        //Obtener el nombre
        String nombre = intent.getStringExtra("nombre");
        
        //Recuperar el TextView por su id
        TextView lblNombre = (TextView)findViewById(R.id.lblNombre);
        
        //Establecer el texto y mostrar nombre
        lblNombre.setText("Tu nombre es: " + nombre);

    }

(De nuevo podríamos y deberíamos haber hecho comprobaciones como que el intent no sea nulo y que exista el valor que buscamos)

En primer lugar hemos recuperado el intent mediante el método getIntent(). Luego hemos obtenido el valor usando el mismo indicador que usamos para guardarlo en la Activity anterior y mediante el método getStringExtra(“indicador”) porque sabemos que es una cadena de texto. Para otros valores habríamos usado otros métodos de Intent, por ejemplo, para recuperar un int (entero) getIntExtra(“indicador”);.

Para finalizar, obtenemos el TextView que mostrará el texto y le asignamos el texto: “Tu nombre es: ” + nombre.

Para llamar a este método, debemos incluir la llamada en el método onCreate de la segunda Activity:

El código completo de ambas Activities:

MainActivity.java

package com.asanchezdiaz.comunicacionjson;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

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

    public void mostrarNombre(View view) {
        //Buscamos el control EditText por su id en el layout activity_main.xml
        EditText txtNombre = (EditText)findViewById(R.id.txtNombre);

        //Leemos el nombre del usuario y lo guadamos
        String nombre = txtNombre.getText().toString();

        //Crearemos un Intent en el que almacenaremos el nombre del usuario
        //y que usaremos para iniciar la nueva Activity

        //Asociamos las dos Activities
        Intent intent = new Intent(this, VerNombreActivity.class);

        //Almacenamos el nombre en el Intent
        intent.putExtra("nombre", nombre);

        //Iniciamos la Activity usando el Intent, que ya lleva el nombre
        startActivity(intent);
    }
}

VerNombreActivity.java

package com.asanchezdiaz.comunicacionjson;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class VerNombreActivity extends AppCompatActivity {

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

    private void mostrarNombreUsuario() {
        //Obtener el Intent que hemos recibido
        Intent intent = getIntent();

        //Obtener el nombre
        String nombre = intent.getStringExtra("nombre");

        //Recuperar el TextView por su id
        TextView lblNombre = (TextView)findViewById(R.id.lblNombre);

        //Establecer el texto y mostrar nombre
        lblNombre.setText("Tu nombre es: " + nombre);

    }
}

El resultado es:

Pantalla 1Pantalla 2Pantalla 3

Próximamente usaremos lo que hemos visto aquí para pasar información más compleja con JSON.

Saludos.

Deja un comentario

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