Conexión de la Interfaz con código Java

“Desarrollo de Aplicaciones Móviles en Android”

Ejercicio Inicial A: Conexión de la interfaz con código Java
En este primer ejercicio, queremos que los alumnos se sientan cómodos escribiendo código en Android, tanto XML como clases y métodos. Para ello, haremos una aplicación muy simple, y le aplicaremos una serie de mejoras. La aplicación consistirá de una única actividad
encargada de recoger dos números, A y B, para poder calcular su módulo y devolverle el
resultado al usuario.
A. Descripción
En este ejercicio, no habrá código inicial, sino que los alumnos deberán crear un nuevo proyecto con SDK mínimo de nivel 8 (Android 2.2 o Froyo), y comenzar a construir la aplicación. Como primer punto a tener en cuenta, y como buena práctica de programación,
nos gustaría separar todas las clases de nuestros proyectos en sub---paquetes, de esta forma, las actividades estarán en un paquete “Activities”, los algoritmos en un paquete “logic”, etcétera. El paquete base “com.alumno.android…” se deja a elección del alumno.

Una vez creado el proyecto, deberíamos abrir el archivo main.xml situado en la carpeta
res/layouts, y veremos que tenemos un layout lineal (LinearLayout), donde los
elementos se van colocando uno debajo del otro. El primer elemento que vemos es un
TextView que tiene como texto un elemento String, éste lo podremos encontrar en la
carpeta res/values/strings.xml, y Eclipse nos abrirá el editor. Como vemos, el
String “hello” tiene un determinado valor. Lo que haremos es cambiarlo, y crearemos dos
strings, “tituloA” y “tituloB”, los cuales utilizaremos para decirle al usuario dónde debe
introducir los números A y B respectivamente. Podemos ponerles de valor “A:” y “B:”.
B. Implementación.
B.1.--- Entrando en código XML
Ahora volvamos al archivo main.xml. Éste es el archivo que define lo que se ve en nuestra actividad, que aunque no hemos visto, sabemos que carga este elemento. Gracias a los
XML, podemos hacer grandes cambios en la interfaz sin tener que cambiar una sola línea de
código. Veámoslo. Bajo el TextView que vemos, vamos a añadir una pareja de TextView y
EditText por cada argumento que necesitamos para calcular el módulo, es decir, una pareja para el argumento A y otra para el argumento B. No tenemos que preocuparnos de mucho,
sólo de escribir el siguiente código bajo el primer TextView:

<TextView android:id="@+id/tvA" android:layout_width="match_parent" android:layout_height="wrap_content">
</TextView>
<EditText android:id="@+id/etA" android:layout_width="match_parent" android:layout_height="wrap_content">

</EditText>
Como vemos, cada elemento tiene tres atributos, el id, su ancho y su alto. Todos los elementos (o views) deben tener definido su ancho y su alto, y los dos valores más conocidos son "match_parent1" (ocupa todo el espacio posible) y “wrap_content" (ocupa sólo el espacio necesario para mostrar tu contenido). De esta forma, lo que les estamos diciendo es que
ambos deben coger todo el ancho que puedan, pero sólo aquella altura que necesiten. ¿Qué
pasa si cambiamos la altura de “wrap_content" a “match_parent"”? Pruébenlo, lo
entenderán enseguida. Ahora, el id. ¿Para qué sirve? El id identifica unívocamente a cada vista dentro del archivo (podemos tener otros esquemas XML y utilizar los mismos ids), y es lo
que nos permite tener acceso a estas vistas desde el código Java, pero eso lo veremos más adelante. Bajo estas dos vistas, necesitamos realizar exactamente lo mismo pero para el argumento B, luego lo único que hay que hacer es copiar el código y ponerlo justo debajo, cambiando los ids de “tvA” a “tvB” y de “etA” a “etB” respectivamente. Si no lo hacemos, no podremos modificar estas vistas desde Java, y además Eclipse nos dirá que el XML está mal
porque hay ids repetidos.

Nótese que no estamos definiendo el atributo text para los TextView. Esto es porque ya hemos visto cómo se hace con el TextView que el ADT crea para nosotros, y queremos que los alumnos vean cómo se asigna el texto a los TextView programáticamente.
Sin embargo, los alumnos pueden probarlo si desean.

Bajo el EditText del argumento B, necesitamos otro TextView, al que pondremos
id “tvResult” para mostrar los resultados, y tampoco le asignaremos atributo text. Bajo este
último TextView, añadimos este código para crear el Botón:




1 Nótese que anteriormente “match_parent" era conocido como “fill_parent",
luego es muy común encontrar este valor en lugar del anterior. A efectos prácticos son
lo mismo, sin embargo la evolución de Android favorece este nuevo nombre.

<Button android:id="@+id/btAction" android:layout_width="match_parent" android:layout_height="wrap_content">

</Button>
Ya tenemos lista la interfaz, y no tendremos que modificar más este archivo para que nuestra aplicación funcione. Se recomienda arrancar la aplicación para ver cómo ha quedado nuestra interfaz.



B.2. Código Java
Ya tenemos que entrar en nuestra única actividad. Vemos que en el constructor hay
una llamada a un método, el setContentView(), que es quien le dice a la Actividad que debe coger el archivo main.xml y transformar el código XML en vistas (en inglés, “inflate the views”). Lo que nosotros haremos es separar este código del constructor, y nos crearemos un método privado:


Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initConfig();
}

private void initConfig() {
setContentView(R.layout.main);

}
Con este código, la aplicación funcionará exactamente igual que antes. Ahora
necesitamos que nuestra aplicación haga algo más que sólo mostrar vistas. Éstas son las
variables que vamos a declarar, y lo haremos justo encima del onCreate():

private static final String LOG_TAG = "ModActivity";

/*
* Variables (referencias)
*/

private EditText editTextA; private EditText editTextB; private TextView textViewA; private TextView textViewB; private TextView result; private Button action;
Lo primero, ¿qué es ese String?. Resulta que Android lleva un registro o “log” llamado LogCat, donde se registran las operaciones que va realizando el Sistema Operativo. Nosotros, los programadores de aplicaciones, podemos contribuir al LogCat escribiendo en él, y para ello queremos identificar unívocamente cada clase que escribe en el LogCat, y para
eso es la etiqueta LOG_TAG. Podemos escribir por distintas razones, para información, para
advertencia, para errores, etc. Lo importante es no abusar de él.

Luego tenemos referencias a los distintos EditText y TextView, pero estas referencias están vacías. Debemos unirlas o enlazarlas a las vistas del esquema. ¿Cómo hacemos esto? Lo hacemos dentro del initConfig():

private void initConfig() {
setContentView(R.layout.main);
// unimos las referencias a las vistas de nuestro layout textViewA = (TextView) findViewById(R.id.tvA);
editTextA = (EditText) findViewById(R.id.etA);
action = (Button) findViewById(R.id.btAction);
// resto
Log.i(LOG_TAG, Fin del initConfig().);
}


Como vemos, estamos llamando al método findViewById de la actividad para que nos devuelva las referencias oportunas; tenemos que hacer un typecast al tipo de vista específico. Como ejercicio, se deja la inicialización de textViewB,editTextB y result, que se hacen justo debajo de la inicialización de action.

Después de esto, queremos poner texto a los TextView; para los dos primeros ya
escribimos los strings, luego sólo tenemos que llamar a los métodos oportunos.

textViewB.setText(getString(R.string.tituloB));

result.setText("Introduzca valores y pulse el botón");
Véase que para el textViewB hemos llamado al método getString() para transformar la entrada XML en un String Java y que para el texto de result hemos escrito directamente la cadena String. Dejamos a los alumnos inicializar textViewA utilizando el otro String declarado en el XML y escribir directamente el texto del botón action.

Ya tenemos los textos, ahora necesitamos hacer algo. Primero, nos declararemos un método privado que devuelve un entero con dos parámetros enteros, a y b, que tiene una sola línea:

private int myMod(int A, int B) {
return A % B;

}
Lo que nosotros queremos es que se realice la operación de módulo cuando se pulse el
botón. Para que esto suceda, deberemos crear un objeto de tipo “OnClickListener” que será llamado cuando el botón sea pulsado, y es en el método OnClick() de este objeto donde pondremos el código de la operación. Esto lo haremos en initConfig(), justo antes de la línea en la que escribimos en el LogCat:

// definimos la acción del botón action.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

String res = "";
String A = editTextA.getText().toString(); String B = editTextB.getText().toString(); int a = Integer.parseInt(A);
int b = Integer.parseInt(B);
res = "Resultado = " + myMod(a,b);
result.setText(res);

  }

});
El código en sí es bastante sencillo. Inicializamos un String para guardar el
resultado, cogemos los dos parámetros como cadenas de caracteres (es necesario el toString() porque el método getText() devuelve un objeto de otra clase), los transformamos en enteros, realizamos la operación módulo, y actualizamos el TextView de
resultado. Ya podemos ejecutar la aplicación, y veremos cómo realiza la operación módulo.
B.3. ProBlemas
A pesar de que funciona, la aplicación no está terminada. ¿Qué ocurre si intentamos realizar el módulo de un número entre cero? ¿Y si introducimos números decimales? Todos estos casos de uso son reales, y si no protegemos nuestra aplicación de ellos, nuestros
usuarios sufrirán de software de poca calidad. Antes de proseguir con la resolución de estos problemas, sugerimos a los alumnos que coloquen un breakpoint dentro del método onClick(), que ejecuten la aplicación en modo depuración, y vean paso a paso cómo falla. Tras el fallo, sugerimos que sea vea el resultado obtenido por el LogCat, donde se verá la excepción producida.

Para protegernos de estos fallos, deberemos escribir código que actúe en caso de
fallos, como el módulo con cero o que insertemos números decimales. Esto se hace insertando
un bloque try/catch:


try {
// código que puede fallar
}
catch (Exception e) {
// código que actuará en caso de fallo
}


Nosotros no diremos qué parte del código del método onClick() va dentro del
bloque try, se lo dejamos a los alumnos, pero sí daremos el código del bloque catch:

catch (Exception e) {
Log.e(LOG_TAG, "Excepción al realizar el módulo de "
+ A + " entre " + B);
res = "Se produjo una excepción.";
Toast toast = Toast.makeText(getApplicationContext(), "Perdón, se produjo una excepcn.",
Toast.LENGTH_LONG);
toast.show();

}
Tras capturar la excepción, escribimos un mensaje de error en el Log para informar de
qué operación ha provocado el error, escribimos un mensaje en el TextView de resultado y provocamos que aparezca una notificación de tipo Toast. ¿Qué es una notificación de tipo Toast? Es una notificación que aparece durante un breve momento en pantalla, y que sólo debemos utilizar cuando estemos seguros de que el usuario está concentrado en nuestra aplicación, o no será perceptible. Con este código, podremos escribir lo que queramos en los EditTexts, la operación fallará pero nuestra Actividad vivirá para contar otra operación.
C. Propuestas de mejora:
--- Pedimos a los alumnos que impidan que los usuarios introduzcan números decimales
en los EditText, esto se hace con un atributo de los mismos en el archivo main.xml.
--- Intentar que los EditText muestren el mensaje “Insertar aquí el Argumento …” cuando estén vacíos. Esto también se hace con un atributo de los EditText en el archivo main.xml, y también será necesario crear los strings oportunos en el archivo strings.xml de la carpeta “Resources”.