2. Elementos básicos

2.1. Estructura de una App

El proyecto se puede dividir en cuatro categorías principales (partiendo de un proyecto diseñado en Java):

  • La carpeta "app/src/main/java/com.proyecto.app" donde se sitúan las clases Java que definen el funcionamiento de la aplicación. Esta carpeta son en realidad tres carpetas ("com", "proyecto" y "app"), una dentro de la otra, pero Android Studio las muestra como una sola.
  • La carpeta "app/src/main/res" que a su vez recoge las siguientes carpetas de recursos (se profundizará en cada una de estas carpetas más adelante):
    • layout: aquí se encuentran los archivos XML que definen el diseño de la app.
    • drawable: recursos de imagen (archivos png, bmp, etc.)
    • menu: archivos XML que definen el diseño de los menús de la aplicación.
    • mipmap: íconos de la app.
    • values: archivos XML que definen los colores, las cadenas de texto o los estilos.
  • El archivo de manifiesto situado en "app/src/main": define aspectos generales de la app como su nombre, el ícono que usa, las actividades de la que se compone, etc.
  • Los archivos "build.gradle" (existe uno en la carpeta "app" y otro en la raíz del proyecto, suele usarse el primero) que definen algunos aspectos referidos a la compilación de la app como dependencias, la versión de SDK mínima y objetivo, etc.

2.1.1. Archivos .java

El funcionamiento de la aplicación se programa dentro de estos archivos. Por cada actividad, Android Studio crea una clase java con su nombre y un archivo de diseño XML.

La estructura básica de una clase de actividad es ésta (Android Studio lo configura automáticamente al crear la primera actividad y siempre que damos al botón derecho del ratón y seleccionamos New > Activity):

package com.ejemplo.app;
import android.support.v7.app.AppCompatActivity;
public class ActividadPrincipal extends AppCompatActivity {
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }
}
  • Primero se indica el paquete al que pertenece la clase, que se ha definido al crear al proyecto.
  • Seguidamente se añaden las importaciones de clases necesarias (Android Studio advierte cuándo es necesario importar una clase y seleccionando el error y apretando Alt+Intro, la añade automáticamente).
  • La clase principal debe ser pública y, en el caso de actividades, debe ser una subclase de una de las superclases de actividades, como AppCompatActivity.
  • La actividad tiene un ciclo de vida que se refleja en los siguientes métodos (se declaran como públicos y de retorno nulo):
    • onCreate(): es el único método obligatorio. Se ejecuta cuando el sistema crea al actividad y pasa al estado de "creada". Por tanto, aquí incluiremos aquellas acciones que deben ejecutarse al inicio. Este método recibe un parámetro Bundle que es un objeto que guarda el estado anterior de la actividad. La acción más relevante es indicar el archivo de diseño que corresponde con esa actividad (setContentView(R.id.activity_main))
    • onStart(): una vez la actividad ha terminado el estado de "creada", pasa al de "iniciada". Hace la actividad visible para el usuario.
    • onResume(): en este estado, la actividad pasa a primer plano y el usuario puede empezar a interactuar con ella. La actividad permanece así hasta que se pierda el foco (pase a segundo plano), por ejemplo cuando el usuario selecciona otra actividad.
    • onPause(): el sistema llama a este método como primera indicación de que el usuario está abandonando la actividad. Se puede usar para pausar o ajustar operaciones que no deben continuar cuando la actividad está pausada.
    • onStop(): cuando la actividad ya no es visible al usuario, el sistema invoca este método.
    • onDestroy(): se ejecuta antes de que la actividad sea destruida.

2.1.2. Layout y recursos

Ya hemos indicado que dentro de la carpeta "res" se incluyen varias carpetas que hacen referencia a distintos tipos de recursos (layout, mipmap, values, etc.). Una característica común de estos recursos es que si queremos usar un recurso distinto para situaciones especiales como distintas resoluciones, otros idiomas, la orientación del dispositivo y otras tenemos que crear una carpeta específica con el nombre del tipo de recurso añadiéndole un guión (-) y el tipo de situación en el que se aplica.

A continuación pondremos algunos ejemplos (en Android Studio, al añadir una nueva carpeta de recursos en la opción correspondiente del menú secundario, aparece una ventana en la que podemos añadir esas situaciones y el programa creara las carpetas correspondientes con los nombres adecuados):

  • layout-land: se aplica cuando el dispositivo está en la orientación apaisada.
  • mipmap-xhdpi: se aplica con altas densidades de pantalla
  • values-es: se utiliza cuando el idioma del sistema es el español.

2.1.2.1. Diseño (layout)

Los archivos donde diseñamos la parte visual de la app pertenecen a la carpeta "layout". Android Studio nos permite seleccionar los distintos elementos y arrastrarlos a su posición sin tener que editar el XML directamente.

El elemento principal del diseño es la base o "layout" (se llama igual que la carpeta). Es el elemento que va a contener los botones, campos de texto, etc. Existen varios tipos de bases: lineal (LinearLayout) en el que cada objeto se sitúa debajo del otro, restringido o relativo (ConstraintLayout) en el que la posición de un objeto se define en relación a otro, (FrameLayout) para albergar fragmentos,...

Dentro de esta base se pueden añadir una gran variedad de elementos, los más usados son los siguientes:

  • Button: botones. Los atributos más importantes son textonClick.
  • TextView: campos de texto no editables. El atributo más relevante es text.
  • EditText: campos de texto editables. Destaca el atributo hint (pista).
  • Toolbar: barra de herramientas superior.
  • ImageView: imágenes.
  • FloatingActionButton: botón flotante.
  • RecyclerView: listas.
  • WebView: visor web.
  • ScrollView: vista que permite hacer scroll (desplazarse verticalmente con el dedo).

2.1.2.2. Otros recursos

Además del "layout" existen otros tipos de recursos:

VALUES
Strings: aquí se indican los textos de la app, junto con sus posibles traducciones. Android Studio proporciona un editor de traducciones (botón derecho en el archivo strings.xml) para facilitar la tarea. En este editor, podemos agregar un nuevo texto con el icono "+". También podemos añadir un idioma con el icono del mundo. Las entradas se componen de una clave y un valor, que es el texto en cuestión.
Colors: permite guardar colores para usarlos en el diseño. Por defecto define los colores básicos de la app. Los colores aparecen con un código hexadecimal RGB (por ejemplo, el verde puro es #00FF00). Al contrario que con los textos, los colores se añaden editando el archivo XML: <color name="clave">#00FF00</color>
Styles: establece estilos completos para la aplicación (los colores, tamaños de las barras de acción, estilos de las alertas, etc.)

MIPMAP
Aquí se añade el ícono de la aplicación, creando carpetas distintas para las posibles densidades de pantalla de los dispositivos. Además de añadir los archivos de imagen, también puede añadirse un XML para especificar algún comportamiento, como íconos cuando la app esté en primer o segundo plano.

DRAWABLE
Se añaden otros recursos de imagen, pudiendo hacer las mismas distinciones de resolución que con los íconos.

MENU
Se incluye el diseño del menú con archivos XML, de forma similar al "layout". Puede ser común para las distintas actividades o puede indicarse un menú concreto para alguna actividad.

2.1.3. El archivo de manifiesto

El archivo de manifiesto (AndroidManifest.xml) define algunos aspectos básicos de la aplicación. Entre éstos se encuentran:

  • El nombre del paquete (propiedad "package" de la etiqueta "manifest").
  • Los permisos que necesita para ejecutarse (conexión de red, almacenamiento externo, etc. Se usa la etiqueta <uses-permission> con la propiedad "android:name" y el nombre del permiso.
<uses-permission android:name="android.permission.INTERNET" />
  • Dentro de la etiqueta <application> definimos el nombre y el ícono de la app, su tema o estilo, las actividades que lo componen, etc. Dentro de las etiquetas de las actividades, se define su nombre de clase, su etiqueta, si es la actividad padre o cuál es.
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher_round"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar">
    <activity
        android:name="com.rs1.globaltest.AddActivity"
        android:label="@string/add"
        android:parentActivityName="com.rs1.globaltest.StorageActivity" />
    <activity android:name="com.rs1.globaltest.MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

2.1.4. El archivo "build.gradle"

Existen dos archivos, uno a nivel de app y otro a nivel de proyecto. El que tiene mayor importancia se encuentra dentro de la carpeta "app". Aquí se definen los parámetros de compilación como: la versión de SDK objetiva y mínima, la versión de la app, la compilación en versión reducida ("minified") y las dependencias necesarias. Android Studio permite modificar algunos aspectos de este archivo a través de opciones en el programa (por ejemplo, en la opción "Project Structure").

2.2. Creación de una interfaz de ejemplo

Partiendo de un proyecto nuevo, vamos a crear la aplicación básica que se suele enseñar para familiarizarse con los conceptos más importantes del desarrollo de Android.

Esta aplicación se compone de dos ventanas: una en la que introduciremos un texto y al darle a un botón, se pasará a otra ventana dónde se mostrará dicho texto. De esta manera, aprendemos cómo funcionan las actividades, cómo diseñar la parte visual de la app y cómo pasar información de una actividad a otra.

Empezaremos seleccionando el archivo "MainActivity.xml" en la ventana Project (si Android Studio no lo ha abierto ya) para añadir un campo de texto y un botón. Android Studio nos ofrece una pestaña llamada "diseño", muy visual e intuitiva, donde añadimos los componentes seleccionando y arrastrando, y otra pestaña "texto" donde podemos modificar el archivo XML directamente. Seleccionamos la categoría Text y dentro el objeto PlainText y lo arrastramos a la posición determinada. Si nuestra base o "layout" es ConstraintLayout, su posición vendrá determinada por los objetos que tiene a su alrededor, en este caso el contenedor o ventana. Saldrán unos círculos en cada uno de los lados que deberemos unir con los bordes de la ventana y asignar un margen (con asignar los lados superior e izquierdo o derecho es suficiente). Estos márgenes aparecerán en la ventana de "Attributes" de la derecha.

Hacemos lo mismo con el botón, situado en su categoría correspondiente. Podemos asignar un "id" tanto al botón como al campo de texto para poder referenciarlos más fácilmente después. Le cambiamos la propiedad "Text" al botón por el texto que queramos mostrar (utiliza los recursos de strings en vez de escribir el texto tal cual, para indicar un recurso se usa @string/clave_del_texto aunque apretando en el botón a la derecha del recuadro de "Text" podemos seleccionar nuestro recurso sin memorizarlo). Podemos hacer lo mismo con la propiedad "hint" (pista) del campo de texto.

Ahora toca programar el funcionamiento en la clase Java correspondiente a la actividad. Creamos un método que sea público y que tenga como parámetro un objeto View, ya que lo va a llamar un botón. Dentro de él, declaramos un objeto EditText que haga una llamada al método findViewById(), cuyo parámetro será la referencia al campo de texto. Las referencias se escriben empezando con R.id. y el id del objeto. Ahora tenemos que capturar lo que hay escrito en el campo de texto. Para ello, creamos un objeto String (cadena de texto) que llamará a los métodos getText().toString() del objeto anterior:

EditText campotexto = findViewById(R.id.campo);
String texto = campotexto.getText().toString();

Ahora tendremos que iniciar la siguiente actividad y pasarle esta información. Primero hay que crearla, por lo que apretamos el botón derecho del ratón en la carpeta "app" y seleccionamos New > Activity > Empty Activity. Podemos añadirle un objeto TextView (dentro de la categoría Text) para que muestre el texto de la anterior actividad. Le cambiamos el atributo id si queremos uno distinto.

Volvemos a la clase de la anterior actividad para que una vez captado el texto, llame a la nueva actividad y le pase el valor. Para ello creamos un objeto de clase Intent y valor newIntent(this, nuevaActividad.class). Después pasamos el valor del campo de texto llamando al método del objeto intent putExtra(nombre, valor). El nombre servirá para identificar de forma única la información que vamos a pasar (es preferible indicar este nombre fuera de la función, justo después de declarar la clase, de forma pública y estática para poder hacer la referencia en la otra actividad más fácilmente) y el valor será el String que hemos creado antes:

public static final String CATEGORY = "com.example.app.TEXT";
...
Intent intent = new Intent(this, nuevaActividad.class);
intent.putExtra(CATEGORY, texto);

Finalmente, iniciamos la nueva actividad con la función startActivity(intent).

No podemos olvidarnos de ir a los atributos del botón y añadir en la propiedad onClick el nombre de la función que hemos creado para que la ejecute cuando hacemos click.

Pasamos a la clase de la segunda actividad. Aquí, dentro del método onCreate() vamos a recoger el texto que hemos mandado creando un objeto Intent con valor getIntent() y un objeto String cuyo valor será un método del objeto Intent: getStringExtra(PrimeraActividad.nombre)

Intent intent = getIntent();
String texto = intent.getStringExtra(MainActivity.CATEGORY);

Ahora ya sólo queda hacer crear un objeto TextView con la referencia al campo de texto de la actividad y que muestre la información que acabamos de recoger (con el método setText()):

TextView textView = findViewById(R.id.texto_resultado);
textView.setText(texto);