lunes, 28 de mayo de 2012

Programación Android: Recursos – Introducción


Ya hemos visto que Android separa los recursos (imágenes, sonidos etc) del código colocándolos organizados dentro del directorio ./res. Esto nos facilita su mantenimiento, además de permitirnos usar diferentes recursos dependiendo de la configuración del telefono.
Separar los recursos permite proporcionar alternativas para dar soporte a las distintas configuraciones de dispositivos, como idiomas o tamaños de pantalla. Para conseguir compatibilidad con las diferentes configuraciones, debemos organizar los recursos en el directorio ./res de nuestros proyectos, dentro de subdirectorios para agruparlos por tipo y configuración.
Un recurso puede usarse por defecto (Se mostrará en cualquier dispositivo, independientemente de su configuración), o pueden especificarse recurosos alternativos (Que se mostrán en los dispositivos para configuraciones determinadas), veámoslo con unas imágenes de ejemplo:
Dos dispositivos distintos, usando recursos por defecto:
Recursos en Android
Dos dispositivos distintos, usando recursos alternativos:
Recursos en Android
Por ejemplo, podemos crear iconos más pequeños para que sean mostrados en los telefonos con pantallas más pequeñas o diseñar una disposición de pantalla diferente para cuando la aplicación se esté ejecutando en modo apaisado, para conseguir esto, simplemente creamos una carpeta de recursos añadiendo el sufijo que indica la situación en la que debe usarse.
Para el caso del idioma, crearíamos un archivo xml con las cadenas traducidas a dicho idioma, en este caso inglés, y lo colocaríamos dentro de ./res/values-en/strings.xml.
Para el caso del layout personalizado cuando la pantalla esté en modo apaisado, meteríamos nuestro layout dentro de res/layout-land/
.
Para saber más acerca de los tipos de sufijos que se pueden usar, visita Providing Resources en la página oficial de Android.
Luego, en la entrada de mañana, continuaremos con màs sobre el manejo de los Recursos dentro de una aplicacion Android.

domingo, 27 de mayo de 2012

Mis disculpas - La autoria!

Gente, buenas noches!
Si, he cometido un grave error, que es no nombrar nunca las fuentes de información, desde donde yo aprendo y busco compartir ese conocimiento.
No es con mala intensión, no es con intenciones de generar dinero ni de quitar credito. Fue solo por no darle importancia a algo tan importante como decir: GRACIAS.
Gracias por tu trabajo.
Gracias por la explicación.
Gracias por el código fuente, las imágenes, el sonido.
Gracias por continuar ayudando a que todos aprendamos.
Gracias a....
http://androideity.com/
http://www.vogella.com
http://www.sgoliver.net/
http://www.xatakamovil.com/

Y a muchos de los autores que no he nombrado hasta el momento. Lo mejor? es que de ahora en adelante, citaré las fuentes y ayudaré a la difusión.
Disculpen quienes no he nombrado, no volverá a pasar. Y agradezco la paciencia y enseñanza que me han brindado. Mis intensiones no fueron ni son malas.

saludos cordiales,
Lic. MAriano Salvetti

Actividades y pasar parámetros entre ellas


Ahora, vamos a ver como crear varias actividades y estudiaremos cómo hacer que se pasen parámetros las unas a las otras.
El proyecto con este ejemplo está disponible, por email, comentado paso a paso: Intents y Bundles
Voy a explicar un poco por encima que hace cada archivo del proyecto:

./res/layout/main.xml

 
< ?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
 
 <textview android:id="@+id/textView1" 
           android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/hello" />
 
 <button android:id="@+id/button1" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/cadena1" />
 
 <button android:id="@+id/button2" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/cadena2" />
</linearlayout>
En este layout principal vamos a agregar dos botones que nos servirán para lanzar las nuevas actividades que creemos después.

./res/layout/segunda_actividad.xml

 
< ?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" 
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 
 <textview android:id="@+id/textView1" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/cadena1" />
 
 <textview android:id="@+id/params" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/hello" />
 
 <button android:id="@+id/boton" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:text="@string/cadena1" />
 
</linearlayout>
Este layout vamos a usarlo para mostrar los parámetros que pasemos de una actividad a otra

./src/mainActivity.java

package com.msalvettitest.actividades;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
 
public class mainActivity extends Activity {
 
   protected static final int REQUEST_CODE = 10;
 
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
 
      // Capturamos los objetos gráficos que vamos a usar
      Button button1 = (Button) findViewById(R.id.button1);
      Button button2 = (Button) findViewById(R.id.button2);
 
      // Fijamos un evento onclick para el button1, cada vez que
      // lo pulsemos se llamará a este método (que abrirá una actividad)
      button1.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            Intent intent = new Intent(mainActivity.this, Activity1.class);
            startActivity(intent);
         }
      });
 
      //button2 pasará parámetros a otra actividad, y los devolverá
      button2.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            Intent intent = new Intent(mainActivity.this, ParametrosActivity.class);
 
            // damos valor al parámetro a pasar
            intent.putExtra("param1", "valor del parámetro 1 (viene de mainActivity)");
            /*
             * Inicia una actividad que devolverá un resultado cuando
             * haya terminado. Cuando la actividad termina, se llama al método
             * onActivityResult() con el requestCode dado.
             * El uso de un requestCode negativo es lo mismo que llamar a 
             * startActivity(intent) (la actividad no se iniciará como una
             * sub-actividad).
             */
            startActivityForResult(intent, REQUEST_CODE);
         }
      });
   }
 
   /*
    * Éste método se llama cuando la actividad que iniciamos con un startActivityForResult
    * finaliza, dandi el REQUEST_CODE con el que llamó, el resultCode se devuelve, junto con
    * algunos datos adicionales, el resultCode será RESULT_CANCELED si la actividad devuelve
    * eso explícitamente, si no devuelve ningún resultado o si la operación finalizó de forma inesperada.
    */
   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == REQUEST_CODE) {
         // tomamos el valor devuelto por la otra actividad
         String result = data.getStringExtra("result");
         // enseñamos al usuario el resultado
         Toast.makeText(this, "ParametrosActivity devolvió: " + result, Toast.LENGTH_LONG).show();
      }
   }
}
En esta clase vamos a modificar el comportamiento de los botones, añadiendoles listeners para cuando el usuario haga click en ellos.
Por último, vamos a crear otras dos actividades, la primera (./src/activity1.java), no va a hacer nada, solo mostrarse. La segunda (./src/ParametrosActivity.java), va a recibir un parámetro y devolver otro.

./src/activity1.java

 
package com.msalvetti.test.actividades;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
 
public class Activity1 extends Activity {
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.segunda_actividad);
 
      // Capturamos los objetos gráficos que vamos a usar
      TextView text = (TextView) findViewById(R.id.textView1);
      Button button = (Button) findViewById(R.id.boton);
 
      // Agregamos al textView un texto
      text.setText(R.string.cadena1);
 
      // Cambiamos el texto al botón
      button.setText(R.string.salir);
 
      // Evento onclick del botón, cuando se pulse, cerramos la actividad
      button.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            finish();
         }
      });
   }
}

./src/ParametrosActivity.java

package com.msalvetti.test.actividades;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
 
public class ParametrosActivity extends Activity {
   private static final int OK_RESULT_CODE = 1;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      // TODO Auto-generated method stub
      super.onCreate(savedInstanceState);
      setContentView(R.layout.segunda_actividad);
 
      // Capturamos los objetos gráficos que vamos a usar
      TextView text = (TextView) findViewById(R.id.textView1);
      Button button = (Button) findViewById(R.id.boton);
      TextView params = (TextView) findViewById(R.id.params);
 
      text.setText(R.string.cadena2);
 
      button.setText(R.string.salir);
 
      //Al pulsar el botón cerramos la ventana y volveremos a la anterior
      button.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            //Cierra la actividad y la saca de la pila
            returnParams();
         }
      });
 
      // Mostramos los parámetros recibidos de la actividad mainActivity
      Bundle reicieveParams = getIntent().getExtras();
      params.setText(reicieveParams.getString("param1"));
   }
 
   protected void returnParams() {
      Intent intent = new Intent();
      intent.putExtra("result", "'Valor devuelto por ParametrosActivity'");
      setResult(OK_RESULT_CODE, intent);
      finish();
   }
}
Es un ejemplo simple, pero que sirve a modo de repaso para practicar el manejo de las actividades y el paso de parametros entre ellas.

sábado, 26 de mayo de 2012

Actividades , Procesos e Hilos en Android


Actividades y tareas


Las actividades conforme se van ejecutando van apilándose en una pila. Cuando finalizamos una actividad, con el método finish() o con la tecla atrás del teléfono, la actividad se extrae de la pila, quedando encima de la pila la actividad que se abrió anteriormente.
Si ejecutamos una actividad varias veces sin cerrarla, ésta aparecerá en la pila tantas veces como la hayamos ejecutado. La pila de actividades se envía al segundo plano cuando la aplicación pierde el foco, y vuelve al primer plano cuando la aplicación vuelve a tomar el control.
Podemos modificar este comportamiento con flags que pasamos al objeto Intent a partir de las propiedades de la activity descritas en el AndroidManifest
Si una pila de tareas se abandona por el usuario durante un periodo de tiempo y el sistema necesita más recursos, se limpia la pila de actividades (excepto la actividad principal), este comportamiento se puede modificar en el manifiesto:

Atributo
Función
alwaysRetainTaskState
Si vale true, se mantiene la pila aunque se abandone durante mucho tiempo
clearTaskOnLaunch
Si es true, se limpia la pila (excepto la actividad principal) cada vez que se lleve al segundo plano
finishOnTaskLaunch
Similar a la anterior, pero solo se aplica a la actividad con este atributo fijado a true.



Procesos e Hilos


Como cada aplicación se ejecuta en un proceso Linux distinto, todos los componentes y procesos de dicha aplicación corren en el mismo hilo. Esto se puede modificar con el atributo process de cada componente (activity, provider, receiver y service). En la etiqueta application del manifest podemos poner este atributo para que sea aplicado a todos sus elementos.
Para gestionar tareas pesadas podemos usar hilos para ejecutar dichas tareas en un hilo aparte (ejecutarlas en segundo plano). Para llevar a cabo esta operación usaremos el objeto Thread de java, aunque Android proporciona otros objetos para facilitar el trabajo, como Handler, AsyncTask o Looper.(entre otros).