Android

Android


ELEMENTOS DE JAVA

Página 18 de 25

APÉNDICE A

ELEMENTOS DE JAVA

Este apéndice contiene una introducción al lenguaje Java necesario para seguir los ejemplos de este libro. Esta introducción a Java es específica para Android. No trataremos los programas Java independientes ni los applets. Por tanto, todos los ejemplos podrán ejecutarse como aplicaciones Android en un emulador o en un teléfono o tablet. Esta aproximación a Java es algo inusual. Existe una idea establecida de que el lenguaje Java debe aprenderse antes que Android y de hecho todos los libros de Android suponen que el lector conoce Java u otro lenguaje similar como C++. Aunque la lógica de primero se empieza a andar y luego a correr es correcta, lo que es desacertado en en el presente caso es asociar a Android con correr. Aunque las aplicaciones profesionales de Android son programas de gran complejidad, esto no impide que se puedan escribir programas sencillos que puedan comprenderse y que permitan aprender el lenguaje. Al aprender Android y Java al mismo tiempo, se evita tener que asimilar conceptos de Java que Android no soporta, por ejemplo, los gráficos y los applets.

A.1. Programa básico de Java con Android

Utilizaremos el programa Eclipse para crear un nuevo proyecto de Android llamado EjemploJava1. Un proyecto de Android contiene un programa de Java y otros datos en una serie de ficheros, que son utilizados por el programa o por el sistema. Un programa de Java es una colección de clases, contenidas en uno o varios ficheros file1.java, file2.java,…. En Android estos ficheros java se almacenan en el directorio src de nuestro proyecto actual. Al crear nuestro nuevo proyecto de Android, se crea la actividad EjemploJava1, almacenada en el fichero EjemploJava1.java, que se encuentra en el directorio src. Al hacer doble click sobre este fichero en el explorador de archivos, se abre en el editor de Eclipse y  nos encontramos con el programa Java más simple:

  package es.ugr.amaro;

  import android.app.Activity;

  import android.os.Bundle;

  public class EjemploJava extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    }

 }

Este es el modelo que utilizaremos como punto de partida en todos nuestros programas Java. Examinemos su estructura:

•   El programa contiene una serie de instrucciones o sentencias. En Java cada instrucción o sentencia debe terminar con un punto y coma. Se pueden escribir varias instrucciones en una línea o una instrucción en varia líneas. Los espacios en blanco son ignorados.

•   La primera línea package es.ugr.amaro.ejemplojava1; indica que esta clase pertenece al paquete es.ugr.amaro. Cada punto en el nombre de un paquete indica un subdirectorio, por lo que nuestro programa Java está contenido en el directorio:

          src/es/ugr/amaro/ejemplojava1

•   Las dos líneas siguientes precedidas por import indican que este programa utiliza dos clases predefinidas en dos paquetes del sistema Android.

          import android.app.Activity;

          import android.os.Bundle;

En este caso, el programa importa la clase Activity del paquete android.app y la clase Bundle del paquete android.os. Android contiene numerosos paquetes con miles de clases. En el editor de Eclipse, cuando escribimos el nombre de una clase, ésta se subraya en rojo si se requiere añadir un import, por lo que no necesitamos recordar el nombre del paquete. Basta pulsar con el botón derecho sobre el nombre de la clase y aparece una lista de opciones, entre ellas la de importar el paquete. La seleccionamos y Eclipse escribirá la instrucción import por nosotros.

•   El programa contiene una clase llamada EjemploJava1 cuya definición abarca el bloque de código comprendido entre la llave inicial y final:

        public class JavaEjemplo1 extends Activity {

        }

Notese que la definición de la clase no termina con punto y coma. Esto es debido a que no se trata de una sentencia o instrucción ejecutable, sino un tipo de  definición. El atributo public indica que la clase es pública y puede ser utilizada externamente. La declaración de la clase finaliza con extends Activity. Esto significa que nuestra clase es una subclase de la clase Activity, definida en el paquete android.app y hereda todas sus propiedades, además de las que nosotros le queramos añadir. Por tanto, JavaEjemplo1 es una extensión o una generalización de la clase Activity. Se dice que Activity es una super-clase de JaveEjemplo1.

•   La siguente línea:

     /** Called when the activity is first created. */

es un comentario. Los comentarios pueden abarcar varias líneas y se delimitan por las parejas de caracteres:

     /**  ...  */

o también:

     /*       */

Las dobles barras // comienzan un comentario hasta el final de la línea.

•   Dentro de la definición de la clase JavaEjemplo1 encontramos la declaración de un método de la clase llamado onCreate.

        @Override

        public void onCreate(Bundle savedInstanceState) {

        }

Este método es una función con un parnámetro llamado savedInstanceState de tipo Bundle. La declaración comienza con la clave @Override, lo que indica que se está redefiniendo o sobreescribiendo el método onCreate de la super-clase. El tipo de acceso del método es public, o público, al que se puede acceder externamente desde otro programa. El método es de tipo void porque esta función no devuelve ningún resultado.

•   Finalmente, entre dos llaves, tenemos la definición del método, que consiste en dos instrucciones:

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

En la pimera, el prefijo super indica ejecutar un método de la super-clase Activity. Por tanto, la instrucción:

   super.onCreate(savedInstanceState)  

ejecuta el método onCreate() de Activity, aplicado sobre el argumento savedInstanceState. La última instrucción ejecuta el método setContentView() tomando como argumento la variable R.layout.main, que es una referencia al fichero main.xml que contiene el layout de la interfaz de usuario que vemos en la pantalla.

Esta es la estructura básica de una actividad o programa de Android, que puede considerarse un molde, o template para todos los programas que escribiremos a continuación. Usaremos siempre el siguiente fichero res/layout/main.xml:

   <?xml version="1.0" encoding="utf-8"?>

   <LinearLayout

   xmlns:android="http://schemas.android.com/apk/res/android"

       android:background="#ffffff"

       android:orientation="vertical"

       android:layout_width="fill_parent"

       android:layout_height="fill_parent"

       >

   <TextView

       android:textColor="#000000"

       android:textSize="18sp"

       android:layout_width="fill_parent"

       android:layout_height="wrap_content"

       android:text="@string/hello"

       android:id="@+id/textView"

       />

   </LinearLayout>

El anterior layout define un campo de texto llamado "textView" que nos permite escribir en la pantalla. A continuación, modificaremos el programa básico para escribir texto en la pantalla como en el siguiente ejemplo.

   package es.amaro.ugr.ejemplojava1;

   import android.app.Activity;

   import android.os.Bundle;

   import android.widget.TextView;

   public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

      TextView textView=

                      (TextView) findViewById(R.id.textView);

      textView.setText(

             "El programa más básico de Java con Android " +

             "escribe un texto en la pantalla con setText.");

      textView.append(

                    " Así se añade más texto con append.");

      textView.append("\nAsí se escribe una segunda línea." );

    }

}

Aquí se define una variable textView que se refiere al campo de texto y permite modificarlo con setText () y añadir más texto con append (). El resultado se ve en la figura A.1.

Figura A.1. Programa básico para escribir texto.

A.2. Variables

Las variables almacenan datos, que pueden ser datos primitivos (números en distintas representaciones) o referencias a objetos (que son conjuntos de datos). Los tipos de datos primitivos son: int, float, double, char, boolean, long, short y byte. Los más importantes pueden almacenar:

•   int. Un número entero entre -2,147,483,648 y +2,147,483,647.

•   float. Un número con decimales entre 3.4e-38 y 3.4e+38.

•   double. Un número en doble precisión entre 1.7e-308 y 1.7e+308.

•   char. Un caracter UNICODE.

•   boolean. Una variable lógica que vale true o false.

Otros tipos de variables importantes son:

•   String. Es una clase para almacenar cadenas de caracteres.

•   void.     Se usa para describir un método que no devuelve ningún valor.

Las variables deben declararse e inicializarse en cualquier punto del programa. Por ejemplo, modifiquemos el programa anterior para declarar e inicializar algunas variables, que escribiremos en pantalla.

  public class EjemploJava1 extends Activity {

     /** Called when the activity is first created. */

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText(

             "Declaración e inicialización de variables ");

         // declaración e inicialización de variables

         int i;

         i=123;

         float x,y=1;

         x=0.5123f;

         double a= 123, b=3.1416e-10;

         char caracter=‘a’;

         boolean esFalso=true;

         String cadena="Esto es una cadena";

         // escribe los valores de las variables

         tv.append("\n i="+i);

         tv.append("\n x="+x+",y="+y);

         tv.append("\n a="+a+",b="+b);

         tv.append("\n caracter="+caracter);

         tv.append("\n esFalso="+esFalso);

         tv.append("\n cadena="+cadena);

     }

 }

El resultado de este programa se ve en la figura A.2. Vemos que pueden declararse varias variables del mismo tipo en la misma sentencia separándolas con comas. Los valores de las variables float deben tener el sufijo "f".

Figura A.2. Declaración e inicialización de variables.

A.3. Conversión de variables

Las valores de las variables se pueden convertir de un tipo a otro. Si la conversión se hace a un tipo más amplio, por ejemplo de int a float, la conversión se realiza implícitamente. Si, al contrario, la conversión se realiza a un tipo más restringido, necesitamos indicarlo explícitamente con una conversión o cast, indicando el nuevo tipo entre paréntesis pues se puede perder información. Por ejemplo:  

   float a = 1.5f;

   int i = (int) a;

En el siguiente ejemplo convertimos un valor de int a float a double y viceversa.

   public class EjemploJava1 extends Activity {

     /** Called when the activity is first created. */

     @Override

     public void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

       TextView tv=(TextView) findViewById(R.id.textView);

       tv.setText(

          "Conversión de variables ");

       // conversion de int a float a double

       int i=125;

       float x=i;

       double d=x;

       tv.append("\n\n Conversion de int a float a double");

       tv.append("\n i="+i);

       tv.append("\n x="+x);

       tv.append("\n d="+d);

       // conversion de double a float a int

       d=0.0123456789e3;

       x=(float) d;

       i=(int) x;

       tv.append("\n\n Conversion de double a float a int");

       tv.append("\n d="+d);

       tv.append("\n x="+x);

       tv.append("\n i="+i);

       }

   }

El resultado de la conversión se ve en la figura A.3

Figura A.3. Conversión de variables.

A.4. Operaciones con variables

Con las variables numéricas se pueden realizar las operaciones aritméticas de suma, resta, multiplicación y división (+,-,*,/). También está definido el resto tras una división (%) y el incremento y decremento en una unidad (++, --).  A continuación, tenemos un ejemplo de utilización de estos operadores algebraicos. El resultado se ve en la figura A.4. Los operadores se pueden combinar para realizar operaciones más complejas. Hay que tener cuidado de incluir los paréntesis necesarios, si no estamos seguros de la preferencia en que se realizan las operaciones. Por ejemplo, la multiplicación se realiza antes que la suma, así que x+y*z=x+(y*z). Se pueden sumar variables de distinto tipo y el resultado es una variable del tipo más amplio. Por ejemplo, la suma de un entero y un float es un float. Si queremos que el resultado de una operación se convierta a un tipo más restingido, debemos preceder la expresión con el nuevo tipo entre paréntesis, poniendo también entre paréntesis, si es necesario, la expresión que se está convirtiendo. Por ejemplo i=(int)(x+y) no es lo mismo que i=(int)x+y. En este último caso, x se convierte a entero antes de sumar. Ante la duda siempre es preferible escribir los paréntesis.

Figura A.4. Operaciones algebraicas con variables.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText(" Operaciones aritméticas\n");

         int i=1,j;

         double x=2,y=3,z;

         // suma

         z=x+y;

         tv.append("\n "+x+" + "+y+" = "+z);

         // resta

         z=x-y;

         tv.append("\n "+x+" - "+y+" = "+z);

         // multiplicacion

         z=x * y;

         tv.append("\n "+x+" * "+y+" = "+z);

         // division

         z=x / y;

         tv.append("\n "+x+" / "+y+" = "+z);

         // resto

         x= 74;

         z = x % y;

         tv.append("\n\n "+x+" / "+y+" da resto = "+z);

         // incremento

         i++;

         tv.append("\n\n i incrementado en uno = "+i);

         i--;

         tv.append("\n i decrementado en uno ="+i);

         // suma de tipos distintos

         tv.append("\n\n Operaciones con tipos distintos");

         z= x+i;

         j= (int) x+i;

         tv.append("\n"+x+"+"+i+"="+z);

         tv.append("\n"+x+"+"+i+"="+j);

         // operaciones más complejas

         z= (x*(y+j)/(x*x+1)-1/y)*(i-x)/y;

         z = z*z;

         tv.append(

            "\n\n Resultado de operación compuesta z="+z);

         }

 }

A.5. Funciones matemáticas

Las funciones matemáticas están definidas como métodos de la clase Math en el paquete java.lang. Este paquete es importado automáticamente. En el siguiente ejemplo utilizamos algunas de las funciones más usuales y el resultado se ve en la figura A.5.

Figura A.5. Funciones matemáticas en Java.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         double x,y,z;

         x=Math.PI;

         tv.setText("x = PI = "+x);

         y=-1;

         tv.append("\n y = "+y);

         tv.append("\n Valor absoluto de y ="+Math.abs(y));

         z=Math.sqrt(x);

         tv.append("\n Raiz cuadr. de x="+z);

         z=Math.log(x);

         tv.append("\n Logaritmo de x ="+z);

         z=Math.exp(x);

         tv.append("\n Exponencial(x) ="+z);

         z=Math.pow(x,3);

         tv.append("\n x al cubo ="+z);

         z=Math.cos(x);

         tv.append("\n coseno de x= "+z);

         z=Math.sin(x);

         tv.append("\n seno de x= "+z);

         z=Math.tan(x);

         tv.append("\n Tangente(x)= "+z);

         z=Math.acos(y);

         tv.append("\n Arcocoseno(y)= "+z);

         z=Math.asin(y);

         tv.append("\n Arcoseno(y)= "+z);

         z=Math.atan(y);

         tv.append("\n Arcotangente(y)= "+z);

         z=Math.max(x,y);

         tv.append("\n Maximo de x e y ="+z);

         z=Math.IEEEremainder(x, y);

         tv.append("\n El resto de x entre y es= "+z);

         z=Math.toDegrees(x);

         tv.append("\n Expresado en grados x= "+z);

         z=Math.toRadians(y);

         tv.append("\n Expresado en radianes y="+z);

     }

 }

Otros métodos de interés son:

•   random() devuelve un número aleatorio entre 0 y 1,

•   los métodos de redondeo hacia arriba ceil(), hacia abajo floor(), que proporcionan números double con cifras decimales nulas,

•   round() redondea un float y lo transforma en el int más próximo, o redondea un double y lo transforma en long.

El siguiente ejemplo hace uso de estos métodos. El resultado se ve en la figura A.6.

Figura A.6. Números aleatorios y métodos de redondeo.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText("Números aleatorios y métodos de redondeo");

         double x,y;

         int i;

         x=2*Math.random();

         tv.append(

             "\n Un número aleatorio entre 0 y 2, \n x= "+x);

         y=Math.ceil(x);

         tv.append("\n ceil(x)= "+y);

         y=Math.floor(x);

         tv.append("\n floor(x)= "+y);

         i=(int) Math.round(x);

         tv.append("\n round(x)= "+i);

         tv.append(

             "\n\n Redondeos hasta cualquier cifra decimal");

         y=Math.round(x*1.e2)/1.e2;

         tv.append("\n redondeado a la segunda cifra  "+y);

         y=Math.round(x*1.e3)/1.e3;

         tv.append("\n redondeado a la tercera cifra  "+y);

         y=Math.round(x*1.e4)/1.e4;

         tv.append("\n redondeado a la cuarta cifra  "+y);

         y=Math.round(x*1.e5)/1.e5;

         tv.append("\n redondeado a la quinta cifra  "+y);

     }

 }

A.6. Bloque if-else

Un bloque es una serie de instrucciones entre los caracteres abrir y cerrar llave:

{ ... }

En Java un bloque se procesa como si se tratara de una sóla instrucción o sentencia. Las variables declaradas dentro de un bloque no están definidas fuera de él.

Los bloques if-else permiten ejecutar instrucciones dependiendo de la relación entre los  valores de ciertas variables. Esta relación se establece mediante el uso de los operadores de comparación, que son:  igual, distinto, mayor, menor, mayor o igual, menor o igual:

==, !=, >, <, >=, <=

También se pueden utilizar variables booleanas, que darán true o false si cierta relación se verifica, por ejemplo:

   float x = 1, y = 2 ;

   boolean condicion = x < y;

Los operadores lógicos entre variables booleanas son: AND, denotado en java:

   & , &&

y OR:

   | ,  ||

Por ejemplo:

   boolean condicion1,condicion2,condicion3,condicion4;

   condicion3 = condicion1 & condicion2;

   condicion4 = condicion1 | condicion2;

La diferencia entre los operadores simples (&) o dobles (&&), es que el simple evalúa ambas condiciones, mientras que el doble evalúa la primera y, si es falsa, no evalúa la segunda.

En el siguiente ejemplo demostramos el uso del bloque if-else y del uso de variables boolean. El resultado en la figura A.7.

Figura A.7. Bloques if-else y uso de variables booleanas.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText(" Bloque if-else \n");

         double x=2,y=3;

         if(x==y){

         tv.append("\n "+x+" = "+y);

         } else if(x>y){

         tv.append("\n "+x+" > "+y);

         } else {

         tv.append("\n "+x+" < "+y);

         }

         tv.append("\n\n Operadores booleanos");

         boolean condicion1= x>1;

         boolean condicion2 = y<5;

         tv.append("\n condicion1 es = "+condicion1);

         tv.append("\n condicion2 es = "+condicion2);

         if(condicion1 & condicion2){

          tv.append("\n Las dos son true simultaneamente: " +

                "\n"+x+" > 1 y "+y+" < 10");

         } else{

         tv.append("\n Una de las dos es falsa");

         }

         }

 }

A.7. Bucles for

El bucle for permite repetir una instrucción normalmente utilizando un índice que se incrementa en cada paso. La instrucción a repetir puede ser una única  sentencia o un bloque delimitado por llaves. Su estructura es la siguiente:

   for ( inicializacion ; condicion ; incremento )

   {

    // bloque de sentencias

    sentencia1;

    sentencia2;

    ...

   }

El argumento de for, entre paréntesis, consta de tres sentencias separadas por un punto y coma. En la primera se inicializa una o varias variables. La segunda es una condición o expresión booleana. Si la condición se verifica, se ejecutará el bloque que viene a continuación. Finalmente se incrementa la variable. Se repite el proceso hasta que la condición deje de verificarse. Las variables declaradas dentro del bucle no están definidas fuera de él.

En el siguiente ejemplo usamos un bucle for para generar una tabla de valores de la función seno entre 0 y 1, figura A.8. Si intentamos escribir el valor de la variable i después del bucle, el compilador de java genera un error: variable no definida.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText("Bucle for");

         double x=10,y = 0;

         for(int i=0; i<10; i++){

          y=Math.sin(i/x);

          tv.append("\n "+i+", sin(i/x)= "+y);

         }

         tv.append(

              "\n Fin del bucle for, i no está definida");

         tv.append("\n y= "+y);

     }

 }

Figura A.8. Bucle for.

A.8. Bucle while

El bucle while es similar al bloque for, pero sólo requiere como argumento una condición o variable booleana. El bucle se ejecuta repetidamente hasta que la condición sea falsa.

   while( boolean )

   {

    // bloque de sentencias

    sentencia1;

    sentencia2;

    ...

   }

En el siguiente ejemplo generamos una tabla de 10 números aleatorios usando un bucle while con una variable que se va incrementando hasta que toma el valor 10, y el bucle finaliza (figura A.9).

Figura A.9. Bucle while.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText("Bucle while");

         int i=0;

         while(i<10){

          // variable no definida fuera del bucle

          double y=Math.random();

          tv.append("\n "+i+", random()= "+y);

          i++;

         }

         tv.append("\n Fin del bucle for, i="+i);

     }

 }

Para mayor control del desarrollo de un bucle, pueden utilizarse además las siguientes sentencias:

•   break. Finaliza el buble.

•   continue. Vuelve al comienzo del bucle.

Por ejemplo en el siguiente programa utilizamos break y continue para controlar la terminación de un bucle, saltando el quinto paso (figura A.10).

Figura A.10. Bucle while usando break y continue.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText("Bucle while");

         int i=0;

         while(true){

          i++;

          // salta al principio del bucle

          if(i==5) continue;

          // finaliza el bucle

          if(i==10) break;

          double y=Math.sqrt(i);

          tv.append("\n "+i+", sqrt()= "+y);

         }

         tv.append("\n Fin del bucle, i="+i);

     }

 }

A.9. Bloques switch

El bloque switch es una alternativa al bloque if-else si queremos realizar una acción dependiendo del valor de una variable, comparándola con una serie de casos. Después de cada caso hay que utilizar break para finalizar el bloque, porque todo lo que viene a continuación se ejecuta siempre sin realizar las comparaciones. He aquí un ejemplo de uso de switch dentro de un bloque for, cuyo resultado se ve en la figura A.11.

  public class EjemploJava1 extends Activity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

         TextView tv=(TextView) findViewById(R.id.textView);

         tv.setText("Bucle switch");

         for(int i=0;i<20;i++){

          switch(i){

          case 5:{

             tv.append("\n pasa por 5");

             break; }

          case 10: {

             tv.append("\n tambien pasa por 10");

             break; }

          case 15:{

             tv.append("\n toma el valor 15");

             break; }

          default:

             tv.append("\n i= "+i);

             }   // fin del bloque switch

         }  // fin del bloque for

     }

 }

Ir a la siguiente página

Report Page