domingo, 27 de abril de 2014

Android - AlarmManager

Anteriormente hemos visto un artículo en el cual se muestra como hacer que una función se ejecute cada cierto tiempo, sin embargo si lo que queremos es que el proceso se ejecute cada cierto tiempo aunque la aplicación se cierre, la manera correcta es usar la clase AlarmManager. A través de esta clase podemos añadir al servicio de alarma de Android llamadas a nuestro proceso. Lo primero que debemos hacer es crear una clase que extienda de la clase BroadcastReceiver y sobreescribir la función onReceiver con las funcionalidades que se deseen.

package com.example.alarmexample;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.Location;

public class ExampleBroadcastReceiver extends BroadcastReceiver {
   
    @Override
    public void onReceive(Context context, Intent intent) {
        // Aquí lo que se quiera ejecutar
        System.out.println("*******Temporizador " + new SimpleDateFormat("HH:mm:ss").format(new Date()));      
    }
}

El segundo paso es modificar el archivo AndroidManifest.xml. De este modo registramos el Receiver.

...
       <activity
            android:name="com.example.alarmexample.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     
       </activity>

        <!-- Registar el Receiver -->
        <receiver
            android:name="com.example.alarmexample.
ExampleBroadcastReceiver"
            android:enabled="true" >
        </receiver>

Finalmente debemos añadir el código necesario para registrar la acción a ejecutarse y para pararla. Suponiendo que se han añadido dos botones a nuestra aplicación el código sería el siguiente:

package com.example.alarmexample;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
   
    private ImageButton btnStart;
   
    private ImageButton btnStop;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        btnStart = (ImageButton) findViewById(R.id.imageButton1);
      
        btnStart.setOnClickListener(new OnClickListener() {
             
            // Acción a ejecutar cada vez que se pulse el botón
            @Override
            public void onClick(View v) {               
                /***********************************************************/
                /***********************************************************/
                /***********************************************************/
                // Registrar el servicio cada 60 segundos
                AlarmManager am = (AlarmManager) MainActivity.this.getSystemService(ALARM_SERVICE);                              
                Intent intent = new Intent(MainActivity.this, ExampleBroadcastReceiver.class);               
                  PendingIntent pendingIntent =
                          PendingIntent.getBroadcast(MainActivity.this, 1234567,
                                  intent, PendingIntent.FLAG_UPDATE_CURRENT);               
                  // Realizar la repetición cada 60 segundos. 

                 // Con el primer parámetro estamos indicando que se continue ejecutando 
                 // aunque el dsipositivo este con la pantalla apagada.
                 // En el segundo parámetro se indica a partir de cuando comienza el scheduler,
                 // en este ejemplo es desde el momento actual
                 // El tercer parámetro indica cada cuanto tiempo.
                 // El cuarto hace referencia al receiver que se va a ejecutar.
                 am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60*1000, pendingIntent);                /***********************************************************/
                /***********************************************************/
                /***********************************************************/
                               
            }
        });    
      
        btnStop = (ImageButton)findViewById(R.id.ImageButton01);
        btnStop.setOnClickListener(new OnClickListener() {
             
            // Acción a ejecutar cada vez que se pulse el botón
            @Override
            public void onClick(View v) {
                /***********************************************************/
                /***********************************************************/
                /***********************************************************/

                // Cancelación
                AlarmManager am = (AlarmManager) MainActivity.this.getSystemService(ALARM_SERVICE);
              
                Intent intent = new Intent(MainActivity.this, com.example.alarmexample.ExampleBroadcastReceiver.class);               
                PendingIntent pendingIntent =
                      PendingIntent.getBroadcast(MainActivity.this, 1234567,
                                intent, PendingIntent.FLAG_UPDATE_CURRENT);               
                am.cancel(pendingIntent);

                /***********************************************************/
                /***********************************************************/
                /***********************************************************/
            }
        });          
    }
}

sábado, 12 de abril de 2014

Android - Planificador de tareas (scheduler)

Para crear una aplicación que se ejecute cada cierto tiempo en Android podemos hacerlo de dos modos diferentes, mediante el uso de timers o mediante el uso de  la clase ScheduledThreadPoolExecutor. En este artículo vamos a usar la clase ScheduledThreadPoolExecutor.

La clase ScheduledThreadPoolExecutor se trata de una implementación de un pool de hilos de ejecución de java.

Para instanciar una un pool de hilos con un número n de hilos podemos usar la clase java.util.concurrent.Executors, que mediante la función newScheduledThreadPool(n) nos retornará un pool con el número de hilos requeridos. Para nuestro ejemplo vamos a pedir un único hilo:

private ScheduledThreadPoolExecutor sch = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);

Otra clase que es importante y que vamos a usar es ScheduledFuture. Esta clase nos permite controlar la acción a ejecutar de modo que en cualquier momento podamos cancelar el scheduler.

        // Definir que una tarea (una instancia del tipo Runnable) se ejecute cada 10 segundos.
        periodicFuture = sch.scheduleAtFixedRate(tarea, 0, 10,  TimeUnit.SECONDS);

Para cancelar la tarea sólo es necesario usar la función cancel de la clase ScheduledFuture.

       periodicFuture.cancel(false);

A continuación  veamos todo el código junto de modo tenemos una clase que cada 10 segundos ejecutará un System.out


package com.ljlg.blogscheduler;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class MySchedule {
    private ScheduledThreadPoolExecutor sch = (ScheduledThreadPoolExecutor) Executors
            .newScheduledThreadPool(1);

    private ScheduledFuture<?> periodicFuture;
  
    public void start() {
        // Tarea que queremos ejecutar
        Runnable tarea = new Runnable() {
            @Override
            public void run() {
                // Tú código aquí
                System.out.println("Probando");
            }
        };

        // Indicar cuando se ejecuta la próxima ejección
        periodicFuture = sch.scheduleAtFixedRate(tarea, 0, 10,
                TimeUnit.SECONDS);
    }

    public void stop() {
        periodicFuture.cancel(false);
    }
}


Finalmente sólo será necesario que instanciemos nuestra clase desde nuestro programa. Por ejemplo si tenemos un programa con un botón de comenzar y otro de parar tendríamos algo como lo siguiente:



public class MainActivity extends ActionBarActivity {
   
    private Button btnStart;
   
    private Button btnStop;
   
    MySchedule sd = new MySchedule();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnStart = (Button) findViewById(R.id.button1);
       
        btnStart.setOnClickListener(new OnClickListener() {
              
            // Acción a ejecutar cada vez que se pulse el botón
            @Override
            public void onClick(View v) {
                sd.start();           
            }
        });    
       
        btnStop = (Button)findViewById(R.id.button2);
        btnStop.setOnClickListener(new OnClickListener() {
              
            // Acción a ejecutar cada vez que se pulse el botón
            @Override
            public void onClick(View v) {
                sd.stop();           
            }
        });    
       
    }
 .........
}



jueves, 3 de abril de 2014

Android - Bases de Datos - SQLite

Cuando trabajamos con Android normalmente usaremos como base de datos SQLite. Para ello usaremos las clases incluidas con las librerías de Android del paquete android.database.sqlite.

Lo primero que tenemos que hacer es crear un clase que extenderá de la clase SQLiteOpenHelper.En esta clase debemos sobreescribir los métodos onCreate y onUpdate. Estos dos métodos se van a ejecutar cuando se crea la base de datos y cuando se actualiza.

A continuación tenemos un ejemplo en el cual se crea una tabla de usuarios y se inserta un usuario al crear la base de datos.

package com.ljlg.programandoblog;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {


    private static final String DATABASE_CREATE = "create table usuarios (" +
            "id integer primary key autoincrement, login text not null," +
            "password text not null);";
   
    public DBHelper(Context context, String name, CursorFactory factory,
            int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // Aquí generamos las tablas necesarias      
        db.execSQL(DATABASE_CREATE);
        db.execSQL("INSERT INTO usuarios (login, password) values ('usr1', 'pwd1');");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }   
}

Una vez que tenemos la clase creada veamos como usarla.

// Instanciamos la clase creada con anterioridad
DBHelper helper = new DBHelper(this, "blogDatabase", null, 1);      
// Recuperamos una instancia de la clase SQLiteDatabaseque nos va servir para operar sobre la base de datos
SQLiteDatabase db = helper.getReadableDatabase();

Para realizar consultas podemos realizarlas con la función rawQuery y pasando una sentencia sql o mediante la función query indicando la tabla, los campos y el filtro a aplicar.


rawQuery sin parámetros:

Cursor result = db.rawQuery(" SELECT id, login, password FROM Usuarios", null);

rawQuery con parámetros:

String[] parametros = new String[] {"usr1"};
Cursor result = db.rawQuery(" SELECT id, login, password FROM Usuarios where login = ?", parametros);

query con parámetros: 

String[] campos = new String[] {"id", "login", "password"};
String[] parametros = new String[] {"usr1"};        
Cursor result = db.query("Usuarios", campos, "login=?", parametros, null, null, null);


A continuación vemos como recorrer los resultados


while (result.moveToNext()) {
  Long id = result.getLong(0);
  String login= result.getString(1);
  String password = result.getString(2);
  System.out.println("[" + id + "][" + login + "][" + password + "]");
 }