Desarrollo de Android Apps - Servicios
En mi primer tutorial voy a hablar sobre algo bastante útil en Android: servicios. Gracias a este componente, vamos a poder ejecutar procesos en segundo plano sin necesidad de la interacción del usuario. Por lo tanto, mientras se hace un uso normal del smartphone, en nuestra aplicación vamos a poder estar leyendo la localización, obtener eventos del calendario, enviar una notificación cuando se cumpla cierta condición, ...
CREAR UN SERVICIO NUEVO
Si trabajamos con Android Studio, lo cual recomiendo, para crear un nuevo servicio simplemente tendremos que hacer clic derecho -> New -> Service -> Service.
Crear un servicio nuevo en Android Studio
De esta forma, el servicio se declarará de forma atuomática en el manifest, y se creará automáticamente la clase que hereda de Service.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jlnavarro.services" > <application android:allowBackup="true" android:label="@string/app_name" . . . <service android:name="com.jlnavarro.services.MyService" android:enabled="true" android:exported="true" > </service> </application> </manifest>
Servicio declarado en el manifest
public class MyService extends Service { @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } }
Clase MyService que hereda de Service
En caso de trabajar con Eclipse, tendremos que crear una clase nueva y hacer esto manualmente.
INICIAR Y DETENER UN SERVICIO
Desde una actividad podemos iniciar o detener un servicio con los métodos startService() o stopService() respectivamente.
startService(new Intent(MyActivity.this, MyService.class)); stopService(new Intent(MyActivity.this, MyService.class));
Métodos para iniciar o detener un servicio
FUNCIONAMIENTO DE UN SERVICIO
Si nos fijamos en el servicio MyService anteriormente creado, apreciamos que existen 4 métodos.
Al iniciar un servicio, en primer lugar se ejecutará el método onCreate(). Posteriormente, se invoca el método onStartCommand(Intent, int, int), que recibe el Intent proporcionado por la actividad. En caso de detener el servicio, se llamará al método onDestroy(). Por último, el método onBind() se emplea para la comunicación entre procesos.
EJEMPLO DE APLICACIÓN
Con el objetivo de comprobar el funcionamiento del servicio creado, vamos a hacer una App muy simple que nos permita activar y desactivar el servicio. Para dotar de alguna funcionalidad a nuestro servicio, haremos que nos muestre la hora actual cada 5 segundos en una Toast.
Lo primero que vamos a hacer es agregar en el layout de la actividad principal un par de botones con los que podamos activar y desactivar el servicio.
Layout de la App
<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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="@string/textDescription" android:id="@+id/textView" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="40dp" /> <Button android:layout_width="100dp" android:layout_height="50dp" android:text="@string/buttonOn" android:id="@+id/buttonOn" android:layout_marginTop="50dp" android:layout_below="@+id/textView" android:layout_alignLeft="@+id/buttonOff" android:layout_alignStart="@+id/buttonOff" /> <Button android:layout_width="100dp" android:layout_height="50dp" android:text="@string/buttonOff" android:id="@+id/buttonOff" android:layout_below="@+id/buttonOn" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" /> </RelativeLayout>
Código del layout
A continuación, desde la actividad principal, iniciaremos o detendremos el servicio dependiendo de si pulsemos el botón On u Off.
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.buttonOn).setOnClickListener(mClickListener); findViewById(R.id.buttonOff).setOnClickListener(mClickListener); } View.OnClickListener mClickListener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()){ case R.id.buttonOn: // Start Service startService(new Intent(MainActivity.this, MyService.class)); break; case R.id.buttonOff: // Stop Service stopService(new Intent(MainActivity.this, MyService.class)); break; } } }; }
Código de la Actividad Principal
Para terminar, definimos un AsyncTask (para más información sobre los AsyncTask, podéis consultar este post) en el servicio anteriormente creado. Desde aquí obtendremos la hora actual cada 5 segundos y la mostraremos con una Toast. En el método onStartCommand() se ejecutará el AsyncTask y en el onDestroy() se cancelará.
public class MyService extends Service { MyTask myTask; @Override public void onCreate() { super.onCreate(); Toast.makeText(this, "Servicio creado!", Toast.LENGTH_SHORT).show(); myTask = new MyTask(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { myTask.execute(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Toast.makeText(this, "Servicio destruído!", Toast.LENGTH_SHORT).show(); myTask.cancel(true); } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } private class MyTask extends AsyncTask<String, String, String> { private DateFormat dateFormat; private String date; private boolean cent; @Override protected void onPreExecute() { super.onPreExecute(); dateFormat = new SimpleDateFormat("HH:mm:ss"); cent = true; } @Override protected String doInBackground(String... params) { while (cent){ date = dateFormat.format(new Date()); try { publishProgress(date); // Stop 5s Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(String... values) { Toast.makeText(getApplicationContext(), "Hora actual: " + values[0], Toast.LENGTH_SHORT).show(); } @Override protected void onCancelled() { super.onCancelled(); cent = false; } } }
Código del Servicio
Dentro de la aplicación, si pulsamos el botón On, observaremos que se muestra la hora actual aunque salgamos de la aplicación. Esto no parará de ejecutarse hasta que volvamos a la aplicación y pulsemos el botón de desactivar el servicio.
Hasta aquí una breve explicación de cómo utilizar servicios en Android, y si tenéis alguna duda, no dudéis en preguntar!
Un saludo!