Home » Android » Una aplicación Android por dentro

Una aplicación Android por dentro

Hemos creado una aplicación Android casi sin esfuerzo, del tipo HelloWorld, que nos servirá analizar el proyecto ya que es lógico que nos preguntemos ¿Qué hay dentro de una aplicación Androdi?; ya que casi no hemos creado nada y en el explorador del paquete aparecen un montón de archivos. 

Como primer paso utilizaremos el explorador del paquete (Package Explorer) de Eclipse. Si hacemos clic en el proyecto podemos visualizar todos los elementos que componen el proyecto. 

Package Explorer

  • src: Contiene los archivos fuente .java de nuestro proyecto. En este caso, Test1Activity.java que tiene el punto de entrada a la aplicación. En este archivo podríamos añadir código para nuestra aplicación.
  • Android 4.1.2: Esta carpeta contiene el archivo android.jar, que, por su parte, almacena todas las bibliotecas de clases necesarias para una aplicación Android.
  • gen: Contiene los archivos R.java y BuildConfig.java, generados por el compilador; el primero de estos archivos hace referencia a los recursos encontrados en el proyecto . Estos archivos no se deben editar manualmente.
  • assets: En esta carpeta encontraremos los recursos no compilados e integrados a la aplicación: archivos de texto, bases de datos, etc.
  • bin: En esta carpeta encontraremos un archivo que estudiaremos con mayor detalle: el manifiesto y también se almacena el paquete de la aplicación (.apk).
  • libs: En esta carpeta se almacena el soporte a la versión 4 en un archivo tipo jar (Java ARchives), estos archivos permiten recopilar en un sólo archivo varios archivos diferentes de código java, almacenándolos en un formato comprimido para que ocupen menos espacio. La ventaja de usar jar (en lugar de zip) es que Java puede ejecutar estos archivos sin necesidad de descomprimirlos previamente. 
  • res: En esta carpeta encontraremos todos los recursos utilizados por la aplicación, esto incluye: animaciones, gráficos, cadenas y archivos.
  • res/drawable-*: Recursos gráficos de iconos de la aplicación en diferentes tamaños para diversos dispositivos.
  • res/layout/main.xml: Archivo de recurso del diseño usado por la actividad para organizar los controles en la pantalla. Son las vistas utilizadas en las diferentes pantallas de la aplicación.
  • res/menu/…: Archivos XML con los menús de la aplicación.
  • res/anim/…: Archivos XML con descripciones de animaciones.
  • res/xml/...: Archivos XML para otros usos.
  • res/values/strings.xml: Archivo de recurso en donde se definen los recursos de cadenas.
  • AndroidManifest.xml: Un archivo xml con el manifiesto de la aplicación, lo que incluye información sobre el paquete, la versión mínima SDK y los permisos; es decir, es el archivo de configuración general para la aplicación. 
  • ic_launcher-web.png: Un recurso de imagen para el icono de inicio de la aplicación.
  • proguard.cfg:  Un archivo que se genera automáticamente y que utiliza Eclipse, ProGuard y ADT. Este archivo es editable para configurar la optimización y la seguridad del código. 
  • project.properties:  Un archivo que genera automáticamente  ADT y que no se debe modificar. Básicamente contiene el nivel SDK de la aplicación.

Principales archivos de un proyecto Android por dentro

Las aplicaciones Android están compuestas de diferentes tipos de archivos y Eclipse-ADT nos da las herramientas para editar el contenido. Algunos archivos son de código Java en los que encontraremos clases y código Java y otros son recursos de tipo gráfico, cadenas, etc. Veamos algunos de los principales archivos en mayor detalle. 


MainActivity.java

La clase Activity es la clase base para el componente visual de esta aplicación; es decir, nuestra clase MainActivity.java se deriva de la clase Activity, que es una clase contenedora de componentes como lo podría ser una ventana o un formulario. 
Si hacemos una analogía al desarrollo de una aplicación de escritorio Visual Basic la clase Activity sería el equivalente  a Form y los controles que colocamos en el formulario en este caso se denominan Views (vistas) que son los componentes visuales activos de nuestra aplicación Android..
Éste es el contenido de la clase MainActivity.java:

package com.libroandroid.test1;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

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.activity_main, menu);
        return true;
    }
    
}

El asistente generó el código de la clase MainActivity y en el método OnCreate incluye una llamada a setContentView que se encarga de desplegar el diseño de la interfaz de usuario a partir de un recurso de tipo layout. Los recursos están almacenados en la carpeta res que posee subcarpetas para subdividir la clase de recursos: menu, layout, values, drawable, etc. Mediante la variable R tenemos acceso a los recursos. 
 
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

res/layout/activity_main.xml


El contenido de este archivo define en formato xml el diseño de la interfaz de usuario:

<RelativeLayout 
    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"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world" />

</RelativeLayout>

En este caso el diseño tiene una organización relativa (depués veremos que existen otros tipos) y TextView es el único componente visual que se define en este caso. Este diseño fue generado automáticamente por el asistente pero nada nos impide crear el diseño e incluir los componentes visuales mediante código java. 
En el código java de nuestras clase podemos utilizar estos componentes visuales accediendo a ellos mediante su identificador (en este caso no se ha definido), por ejemplo, para cambiar el valor de una propiedad.
Todas las propiedades de los componentes visuales (por ejemplo, TextView) se pueden asignar en el archivo de recursos de tipo layout y también desde código java. No obstante se recomienda dar preferencia a la asignación en los archivos de recursos de tipo layout para mantener mayor independencia entre lógica y presentación.

Asignaremos un identificador (TV01) al componente TextView:
   …
<TextView
        android:id="@+id/TV01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world" />

</RelativeLayout>

Ahora podremos acceder al componente de la interfaz se puede utilizar el método findViewById():

TextView objTV = (TextView) findViewById(R.id.TV01);

El manifiesto contiene detalles sobre la configuración de la aplicación.


Archivo de manifiesto (AndroidManifest.xml)

El archivo de manifiesto es el principal archivo de configuración de la aplicación Android. Al hacer doble clic en el archivo AndroidManifest.xml en el panel de la izquierda de Eclipse (Package Explorer) para que se inicie el editor del archivo.

Datos del manifiesto

Tal como se puede observar, el editor del archivo de manifiesto tiene 5 pestañas, en cada una se pueden editar datos específicos:

  • Manifest (Manifiesto): En esta pestaña se muestran los datos de configuración general, por ejemplo, nombre del paquete e información de la versión mínima del SDK de Android requerida por la aplicación.
  • Application (Aplicación): En esta pestaña se definen detalles de la aplicación: nombre, icono, actividades que se ejecutan, filtros de intentos y las funcionalidades y servicios prestados por la aplicación. 

Manifiesto de la aplicación

  • Permissions (Permisos): En esta pestaña se definen las reglas de los permisos requeridos por la aplicación. 
  • Instrumentation (Instrumentación): Android SDK incluye una serie de clases de instrumentación que nos asisten en las pruebas, en esta pestaña se pueden añadir o quitar estos componentes.
  • AndroidManifest.xml: En esta pestaña se puede editar manualmente el archivo cumpliendo con su formato XML. 

Lo que modifiquemos en cualquiera de las primeras cuatro pestañas lo veremos reflejado en el archivo AndroidManifest.xml, que también podemos modificar de modo directo. 

Es más seguro modificar el archivo de manifiesto desde las 4 primeras pestañas ya que así evitaremos los errores de sintaxis que se pueden provocar en una edición manual desde la quinta pestañas.


Ahora veremos qué es lo que encontramos dentro del archivo del manifiesto de la aplicación, AndroidManifest.xml. El archivo siempre comienza con la etiqueta <?xml….>:

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

Los datos del manifiesto se encierran entre etiquetas <manifest> y </manifest>. En la etiqueta <manifest> contiene atributos para asignar el nombre del paquete y el valor mínimo del SDK de Android. versionCode generalmente comienza con el valor 1 y se incrementará en 1 en cada nueva publicación de la aplicación. El sistema Android no utiliza este valor pero es importante para el desarrollador y para Google Play Store (ya veremos más adelante cómo se publica una aplicación y ahí se explica el uso de este dato por parte de los distribuidores de los paquetes). El valor  minSdkVersion en este caso es la versión 8 y la versión a la que va dirigida es 16:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.libroandroid.test1"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

   
El valor 1 de minSdkVersion se corresponde con Android 1.0 SDK y actualmente el último es el valor 17 que se corresponde con Android 4.2 del SDK . Cada vez que se publica un nuevo SDK de Android se actualiza la lista en http://developer.android.com/guide/appendix/api-levels.html.
El atributo android:icon es un icono que representa a la aplicación mediante un gráfico; el valor asignado es un recurso de tipo gráfico almacenado en la carpeta /res/drawable.
El atributo android:label es una cadena que representa el nombre de la aplicación. Este atributo se puede asignar directamente una cadena entre comillas o, tal como se muestra en este ejemplo, utilizando un recurso de cadena. Más adelante estudiaremos cómo es la nomenclatura de los recursos de la aplicación.
En este caso no se usa el atributo android:description pero podría incluirse con una cadena descriptiva de la aplicación.

    …
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
    …

Las aplicaciones Android están compuesta por una cantidad variable de actividades (puede ser 1 o más). Cada actividad debe registrarse con su nombre de clase en el archivo de manifiesto para que se pueda ejecutar en un dispositivo. Cada actividad representa una tarea y normalmente una pantalla; cada actividad, que se inicia mediante el uso de un mecanismo denominado Intent (que estudiaremos en el capítulo 3), tiene un nombre y un icono (o utiliza el que corresponde a la aplicación). 
Cada actividad se registra con la etiqueta <activity> mediante su nombre de clase, si es necesario se debe incluir el nombre del paquete.  
        
         …
        <activity
           android:name="com.libroandroid.test1.MainActivity"
           android:label="@string/app_name" >
        …

            
  El filtro Intent se utiliza para indicar una actividad como punto de entrada principal de la aplicación. Para la definición de una actividad como predeterminada se utiliza como tipo de acción MAIN y LAUNCHER como categoría.

                     <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category 
                android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Resumiendo, en el manifiesto de la aplicación tenemos la siguiente información:

  • Nombre del paquete: com.libroandroid.test1
  • Versión de la aplicación: Identifica el número de versión de la aplicación.
  • Nombre de la versión: Identificador de tipo cadena con el número de la versión que se visualiza al usuario.
  • Icono: Archivo .png utilizado por la aplicación, almacenado en la carpeta drawable.
  • Nombre de la aplicación: Definido como recurso de cadena en strings.xml.
  • Actividad definida en la aplicación: En este caso hay sólo una actividad, Test1.MainActivity. Dentro de esta actividad aparece un elemento <intent-filter>. El filtro action indica que esta actividad sirve como punto de entrada de la aplicación. El filtro category indica que esta aplicación se puede iniciar desde el icono Launcher del dispositivo.
  • Versión del sdk: Especifica la versión mínima requerida del sistema operativo Android para que esta aplicación se pueda ejecutar.

El atributo android:versioncode se usa para comprobar si una aplicación se puede actualizar, si contiene un valor numérico significa que es actualizable.

Gestión de los permisos de la aplicación

La plataforma Android se basa en el kernel Linux y, por lo tanto, el modelo de seguridad de Android también se basa y amplía el sistema integrado de seguridad de Linux. 
Cada aplicación se ejecuta utilizando una cuenta de usuario propia y tiene sus correspondientes carpetas y archivos. Una aplicación puede acceder sin necesidad de permisos a sus carpetas y bases de datos pero las aplicaciones que necesiten acceder a recursos compartidos o privilegiados del dispositivo deben ser incluidas con sus permisos en el archivo de manifiesto. Todo esto se gestiona en la ficha Permissions del editor del recurso del manifiesto, que permite hacerlo con un asistente, el que finalmente deja reflejada la modificación en el archivo XML del manifiesto, o se puede hacer directamente sobre el código XML. 
Por ejemplo, si una aplicación necesita utilizar la cámara del dispositivo y además poder hacer llamadas debe tener declarados esos permisos en el manifiesto:
 …
<uses-permission android:name="android.permission.CAMERA">
</uses-permission>
<uses-permission android:name="android.permission.CALL_PHONE">
</uses-permission>
 …

Permisos en el manifiesto
Existen varias categorías predeterminadas de permisos, cada una con diversos niveles de permisos (lectura, escritura, etc.):

  • Servicios basados en la ubicación
  • Acceso a la base de datos de contactos
  • Realizar llamadas
  • Envío y recepción de SMS
  • Acceso a la configuración de audio
  • Acceso a la configuración de Wi-Fi
  • Acceso a componentes del dispositivo

Cuando el usuario instala la aplicación se informa qué permisos requiere la aplicación y se da la posibilidad de que el usuario acepte o rechace esos permisos.


Archivos de recursos

En el archivo res/layout/main.xml están definidos los elementos gráficos y los valores de sus propiedades. Veamos un fragmento del archivo main.xml:

 <TextView
        android:layout_width="wrap_content"

  android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world" />

La propiedad android:text se asigna con un recurso de tipo string (cadena) y que se denomina hello_world. Esto significa que este valor está definido como recurso, con el contenido que corresponda, en el archivo res/values/strings.xml:

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

    <string name="app_name">Test1</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>

</resources>

Al hacer clic en el archivo res/values/strings.xml podemos visualizar el contenido de dos modos: gráfico o xml. El modo xml y lo hemos visto más arriba; si hacemos clic en la pestaña Resources podremos visualizar los recursos de cadena en modo gráfico:
 Recursos Android

El archivo strings.xml almacena todas las cadenas y constantes de nuestra aplicación.


También podríamos definir una cadena de modo directo sin necesidad de utilizar el recurso, tal como hacemos en el siguiente elemento TextView: 

 <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Mi primera aplicación Android"
    />

De las dos posibilidades mostradas para definir una cadena es preferible la primera, la que utiliza el identificador @strings. Este enfoque tiene tres ventajas: las cadenas están centralizadas en un sitio del programa, es más simple localizar la aplicación a otros idiomas y podemos reutilizar la cadena con mayor facilidad.


Archivo R.java


El archivo R.java lo genera y actualiza automáticamente el propio Eclipse cada vez que añadimos recursos al proyecto: 
 
/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.libroandroid.test1;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class id {
        public static final int menu_settings=0x7f070000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int activity_main=0x7f060000;
    }
    public static final class string {
        public static final int app_name=0x7f040000;
        public static final int hello_world=0x7f040001;
        public static final int menu_settings=0x7f040002;
    }

Tal como se indica en el código no debemos modificar este archivo ya que lo gestiona Eclipse de modo automático.


ERROR en la compilación ¿Desapareció el archivo R.java?


En muchas ocasiones Android nos hace una mala jugada y hace desaparecer el archivo R.java de la carpeta gen y esto provoca que la aplicación se llene de errores de compilación dado que no se puede resolver ninguna referencia a recurso. 
El problema es que el archivo R.java se genera automáticamente: no podemos añadirlo "a mano" ni tampoco es solución importar la definición de la clase R.
Normalmente una de las causa del error de Eclipse o Android es que alguno de nuestros recursos está mal definido; por ejemplo, un archivo xml con el nombre de archivo escrito con alguna mayúscula. Ante este tipo de problema la solución es revisar las definiciones dentro de la carpeta res y corregir el error; al recompilar el archivo R.java aparecerá nuevamente de modo mágico. 

 

izq sup der

Deja un comentario