Un service es un componente de la aplicación android que representa:

  1. Un deseo de las aplicaciones de realizar operaciones de larga duración mientras no se interactúa con el usuario.
  2. Un componente para suministrar funcionalidad a otras aplicaciones.

¿Cuándo debo usar un Service?

Utiliza un servicio si tienes una operación de larga duración o una tarea que tiene un ciclo de vida largo. Es un buen diseño que las operaciones de larga duración se ejecuten en segundo plano.

Un ejemplo es una tarea de sincronización de datos en segundo plano.

En ese tipo de tarea puedes crear un servicio que se ejecute periódicamente o cuando sea necesario. Puedes hacer uso de una alarma del sistema.

Entonces tu servicio puede terminar cuando la tarea haya terminado.

Hacer el trabajo en segundo plano libera al thread principal de tener que hacer estas tareas, evitando así que la interfaz de usuario se congele cada vez que se ejecuta una tarea intensiva.

Aunque podemos crear un nuevo thread incluso dentro de una actividad, una forma mucho mejor y más limpia es delegar las operaciones en segundo plano a un service.

¿Dónde se ejecuta el Service?

Todos los componentes de android, incluido el service, se ejecutan en el thread principal de la aplicación.

El ciclo de vida de Service es diferente al de Activity. El primero está mejor adaptado para manejar operaciones de larga duración que el segundo.

Una vez que hemos movido nuestras operaciones de larga duración a un thread de fondo, podemos iniciar y manejar ese thread dentro del service.

Las operaciones de larga duración que no requieren la interacción del usuario son las mejores candidatas para delegarlas en un service.

Ventajas de un Servicio

  1. El Service nos proporciona un mecanismo más eficiente para desacoplar las operaciones de larga duración de la interfaz de usuario.

Ejemplos de uso de un Servicio

(a). Servicios sin entrada del usuario
  1. Las aplicaciones que utilizan la red con frecuencia para sondear las actualizaciones.
  2. Aplicación de reproducción de música.
  3. Aplicación de mensajería.
(b). Servicios con entrada del usuario
  1. Aplicación para compartir fotos.

Snippets rápidos de Servicios y How-to's

1. Cómo iniciar un Servicio

En el primer ejemplo se nos ha dado el nombre de la clase:

    public static void startService(String className) {
        try {
            startService(Class.forName(className));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

En el segundo ejemplo se nos ha dado la propia clase y el contexto:

   public static void startService(Class<?> cls, Context context) {
        Intent intent = new Intent(context, cls);
        context.startService(intent);
    }
2. Cómo detener un Servicio

Digamos que quieres parar un servicio y te han dado el nombre de la clase:

    public static boolean stopService(String className) {
        try {
            return stopService(Class.forName(className));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

¿Y si te han proporcionado la propia clase?

    public static boolean stopService(Class<?> cls, Context context) {
        Intent intent = new Intent(context, cls);
        return context.stopService(intent);
    }
3. Cómo enlazar un Servicio

Tenemos dos ejemplos. Aquí está el primero:

    public static void bindService(String className, ServiceConnection conn, int flags) {
        try {
            bindService(Class.forName(className), conn, flags);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

y el segundo ejemplo:

    public static void bindService(Class<?> cls, ServiceConnection conn, int flags,Context context) {
        Intent intent = new Intent(context, cls);
       context.bindService(intent, conn, flags);
    }
4. Cómo desvincular un Servicio

    public static void unbindService(ServiceConnection conn,Context context) {
        context.unbindService(conn);
    }

5. Como obtener todos los Servicios en ejecución

Quieres obtener todos los servicios en ejecución en el sistema y devolver sus nombres como un Set.

    public static Set getAllRunningService(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningServiceInfo> info = activityManager.getRunningServices(0x7FFFFFFF);
        Set<String> names = new HashSet<>();
        if (info == null || info.size() == 0) return null;
        for (RunningServiceInfo aInfo : info) {
            names.add(aInfo.service.getClassName());
        }
        return names;
    }

Ejemplos rápidos de Servicios

1. Cómo cargar canciones en un ArrayList en un Servicio

Tenemos que hacer esto en un thread de fondo ya que no queremos congelar nuestra interfaz de usuario.

Registraremos estas canciones pero por supuesto puedes renderizarlas en un recyclerview o listview e implementar una clase para reproducirlas.

Primero vamos a empezar por definir un objeto Song. Esta es nuestra clase Song bean:

public final class Song {

    private String name;

    private String artist;

    private String coverUri;

    private long time;

    private String location;

    public String getName() {
        return name;
    }

    public Song setName(String name) {
        this.name = name;
        return this;
    }

    public String getArtist() {
        return artist;
    }

    public Song setArtist(String artist) {
        this.artist = artist;
        return this;
    }

    public String getCoverUri() {
        return coverUri;
    }

    public Song setCoverUri(String coverUri) {
        this.coverUri = coverUri;
        return this;
    }

    public long getTime() {
        return time;
    }

    public Song setTime(long time) {
        this.time = time;
        return this;
    }

    public String getLocation() {
        return location;
    }

    public Song setLocation(String location) {
        this.location = location;
        return this;
    }

    @Override
    public String toString() {
        return String.format("name = %s, artist = %s, location = %s",
                name,
                artist,
                location);
    }
}

Luego procedemos a crear nuestro Servicio.

Se comienza creando una clase que implemente el Servicio:

public class ScanMusicService extends Service {...}

Normalmente cuando se crea un servicio el método onCreate() del ciclo de vida es invocado por el sistema.

Aquí es donde iniciaremos un thread que escaneará nuestras canciones y las cargará en un arraylist en el thread de fondo:

    @Override
    public void onCreate() {
        super.onCreate();

        new Thread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Song> songs = scanSongs(ScanMusicService.this);
                LogUtils.d(songs);
                ToastUtils.showLongToast(songs.toString());
            }
        }).start();

    }

El método scanSongs() se encargará de escanear y llenar nuestro arraylist de canciones.

Aquí está la clase completa:

import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.IBinder;
import android.provider.MediaStore;
import android.support.annotation.Nullable;

import com.jiangkang.tools.bean.Song;
import com.jiangkang.tools.utils.LogUtils;
import com.jiangkang.tools.utils.ToastUtils;

import java.util.ArrayList;

public class ScanMusicService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();

        new Thread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Song> songs = scanSongs(ScanMusicService.this);
                LogUtils.d(songs);
                ToastUtils.showLongToast(songs.toString());
            }
        }).start();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    private ArrayList<Song> scanSongs(Context context) {
        ArrayList<Song> result = new ArrayList<>();
        ContentResolver resolver = context.getContentResolver();
        Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                null,
                null,
                null,
                null);
        if (cursor != null && !cursor.isClosed() && cursor.moveToFirst()) {
            while (cursor.moveToNext()) {
                String songName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
                String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
                String location = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));

                Song song = new Song();
                song.setName(songName)
                        .setArtist(artist)
                        .setLocation(location);
                LogUtils.d(song.toString());
                result.add(song);
            }
        }
        return result;
    }
}

Y esta es la clase que nos ayudará en la carga de canciones.

2. Cómo utilizar el gestor de descargas del sistema y el Service para descargar

Queremos ver cómo crear un service que pueda descargar datos utilizando el System DownloadManager.

Vamos a ponernos manos a la obra. Primero empezamos creando un service androide:

public class DownloadService extends Service {

Luego procedemos a crear varias clases y campos de instancia en esa clase:

    private BroadcastReceiver receiver;
    private DownloadManager dm;
    private long enqueue;
    private String downloadUrl = "http://192.168.3.186/StaffAssistant.apk";
    private static String apkname = "StaffAssistant.apk";

Estos son:

  1. BroadcastReceiver - nuestra instancia de receptor de emisión.
  2. DownloadManager - Nuestro gestor de descargas del sistema.
  3. enqueue(long) - El identificador único de la tarea de descarga asignado por el gestor de descargas del sistema, que puede utilizarse para consultar o procesar la tarea de descarga a través de este identificador.
  4. Download URL - url donde descargar el apk.
  5. ApK name - nombre de la aplicación

Recuerda que habíamos extendido el service y aún no habíamos implementado ninguno de los métodos que necesitamos anular. Aquí tenemos uno:


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

Ahí devolvemos null y pasamos a nuestro onStartCommand().

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ....

Allí, en primer lugar, recibiremos nuestra cadena de url de descarga a través de Intent.

Luego instanciaremos nuestra clase BroadcastReceiver y anularemos el método onReceive().

        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                install(context);
            }
        };

Dentro del método onReceive() puedes ver que estamos invocando el método install(). Ese método es un método personalizado que crearemos y que instalará nuestra aplicación.

Fuera de nuestro método onReceive() registraremos nuestro BroadcastReceiver, ya que es un componente de android.

registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

Claramente puedes ver que lo hemos registrado programáticamente dado que lo habíamos creado como una clase anónima.

Luego invocamos el método startDownload(), otro método personalizado que crearemos más adelante.

startDownload ( downloadUrl );

Tenga en cuenta que esto requiere una tarjeta SD con permisos de escritura. Si estás usando un targetSDKVersion mayor o igual a 23, entonces puedes usar el permiso dinámico.

Veamos ahora cómo instalar programáticamente la aplicación después de haberla descargado.

Primero creamos el método install(). Recibirá un objeto Context que nos permitirá invocar el método startActivity().

    public static void install(Context context) {

Luego instanciamos un java.io.File. Le pasamos la ruta donde vamos a crear el archivo y el nombre del mismo:

        File file = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                , apkname);

Luego creamos un objeto Intent:

        Intent intent = new Intent(Intent.ACTION_VIEW);

Como la actividad no se inicia en el entorno Activity, establece la siguiente etiqueta:

        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Si la versión es superior a la 7.0.

        if (Build.VERSION.SDK_INT >= 24) {

A continuación invocamos el método getUriForFile() de la clase FileProvider. Estos incluyen:

  1. Contexto.
  2. Dirección del host del proveedor.
  3. El archivo a instalar.

            Uri apkUri =
                    FileProvider.getUriForFile(context, "com.hzecool.slhStaff.fileprovider", file);
            //Adding this sentence means temporarily authorizing the file represented by the Uri to the target application.
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file),
                    "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }

Luego venimos y sobrescribimos el método onDestroy() de la clase Service.Aquí estamos desregistrando nuestro BroadcastReceiver.

    @Override
    public void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

Veamos ahora cómo descargar.
Primero vamos a crear el método startDownload():

    private void startDownload(String downUrl) {

Primero vamos a obtener el DownloadManager del sistema:

        dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

Comenzamos instanciando la clase DownloadManager.Request. Mientras la instanciamos, parseamos nuestra url de descarga usando el método parse() de la clase Uri, y la pasamos a nuestra clase Request:

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl));

Luego establecemos nuestro tipo mime o tipo de archivo como APK usando el método setMimeType():

        request.setMimeType("application/vnd.android.package-archive");

Luego establecemos el destino de nuestra descarga usando el método setDestinationInExternalPublicDir(). En este caso utilizamos el directorio de descargas.

        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkname);

Invocamos la función setNotificationVisibility() para indicar si se mostrará una notificación cuando se complete la descarga.

        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

Luego establecemos el título

        request.setTitle("Download new version");

Por último, pero no menos importante, realizamos la descarga y devolvemos el id único de la tarea

        enqueue = dm.enqueue(request);
    }
}

Aquí está el código completo para el service:

import android.app.DownloadManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;

import java.io.File;

public class DownloadService extends Service {
    private BroadcastReceiver receiver;
    private DownloadManager dm;
    private long enqueue;
    private String downloadUrl = "http://192.168.3.186/StaffAssistant.apk";
    private static String apkname = "StaffAssistant.apk";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        downloadUrl = intent.getStringExtra("downloadUrl");
        if (TextUtils.isEmpty(downloadUrl)) {
            apkname = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1, downloadUrl.length());
        }
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                install(context);

            }
        };
        registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        startDownload(downloadUrl);
        return Service.START_STICKY;
    }

    public static void install(Context context) {
        File file = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                , apkname);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= 24) {
            Uri apkUri =
                    FileProvider.getUriForFile(context, "com.hzecool.slhStaff.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file),
                    "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

    private void startDownload(String downUrl) {
        dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl));
        request.setMimeType("application/vnd.android.package-archive");
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkname);
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setTitle("Download new version");
        enqueue = dm.enqueue(request);
    }
}

Ejemplos de Servicio completo

Veamos los ejemplos completos independientes que puedes descargar y ejecutar.

1. Ejemplo de Servicio simple

MainActivity.java

Esta es la actividad principal. Esta clase deriva de la AppCompatActivity y es responsable de nuestra interfaz de usuario.

Aquí hay algunas definiciones de la API que tal vez no conozcas:

(a). SeviceConnection

Se trata de una interfaz que reside en el paquete android.content y que sirve para monitorizar el estado de un servicio de la aplicación.

(b). IBinder

IBinder es la interfaz base para los objetos removibles, la parte central de un mecanismo ligero de llamadas a procedimientos remotos diseñado para obtener un alto rendimiento cuando se realizan llamadas dentro del proceso y entre procesos.

package com.example.ankitkumar.boundservice;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    BoundService myService;
    boolean isBound = false;

    TextView currenttime, time, date;
    Button btn_start_service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Set the activity content from a layout resource
        setContentView(R.layout.activity_main);
        time = (TextView) findViewById(R.id.tv_time);
        date = (TextView) findViewById(R.id.tv_date);
        currenttime = (TextView) findViewById(R.id.textView_current_time);
        btn_start_service = (Button) findViewById(R.id.button_start_service);
        Intent intent = new Intent(MainActivity.this, BoundService.class);

        /*
        Connect to an application service
        Automatically create the service as long as the binding exists
        */
        bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
    }

    public void getcurrenttime(View view) {
        currenttime.setText(myService.getCurrentTime());
        time.setVisibility(View.VISIBLE);
        date.setVisibility(View.VISIBLE);
    }

    //Setting Up BoundService
    private ServiceConnection myConnection = new ServiceConnection() {

        //Service Connected
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            BoundService.MyLocalBinder binder = (BoundService.MyLocalBinder) service;
            myService = binder.getService();
            isBound = true;
        }

        //Service is Disconnected
        public void onServiceDisconnected(ComponentName arg0) {
            isBound = false;
        }

    };

}

BoundService.java

Esta es nuestra subclase service.

package com.example.ankitkumar.boundservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

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

public class BoundService extends Service {

    //Base interface for a remotable object, the core part of a lightweight remote procedure call mechanism
    private final IBinder myBinder = new MyLocalBinder();

    //Binding Service
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return myBinder;
    }

    //Formatting and parsing dates in a locale-sensitive manner
    public String getCurrentTime() {
        SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm:ss  dd/MMM/yyyy", Locale.US);
        return (dateformat.format(new Date()));
    }

    class MyLocalBinder extends Binder {
        BoundService getService() {
            return BoundService.this;
        }
    }
}

activity_main.xml

El diseño principal de la actividad.

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

<RelativeLayout
    tools_context="com.example.ankitkumar.boundservice.MainActivity" android_background="#efedef" android_layout_height="match_parent" android_layout_width="match_parent" android_id="@+id/activity_main"  >

<TextView
    android_layout_height="wrap_content" android_layout_width="100sp" android_id="@+id/tv_time" android_visibility="gone" android_textStyle="bold" android_textSize="18sp" android_textColor="@android:color/background_dark" android_text="@string/time" android_gravity="end" android_fontFamily="sans-serif-condensed" android_layout_marginTop="40sp"/>

<TextView
    android_layout_height="wrap_content"
     android_layout_width="140sp" android_id="@+id/tv_date" android_visibility="gone" android_textStyle="bold" android_textSize="18sp" android_textColor="@android:color/background_dark" android_text="@string/date" android_gravity="bottom" android_fontFamily="sans-serif-condensed" android_layout_marginTop="40sp" android_layout_alignParentRight="true" android_layout_alignParentEnd="true"/>

<TextView
    android_layout_height="wrap_content" android_layout_width="match_parent" android_id="@+id/textView_current_time" android_textSize="36sp" android_textColor="#ee6f64" android_gravity="center" android_fontFamily="sans-serif-condensed" android_layout_marginTop="70dp" android_hint="@string/time_label" android_layout_centerHorizontal="true"/>

<Button
    android_background="#e54048" android_layout_height="60sp" android_layout_width="200sp" android_id="@+id/button_start_service" android_textStyle="bold" android_textSize="18sp" android_textColor="#ffff" android_text="@string/show_time" android_fontFamily="sans-serif-condensed" android_onClick="getcurrenttime" android_layout_centerInParent="true"/>

</RelativeLayout>

Descarga el código de abajo.

No. Ubicación del enlace.
1. GitHub 2. [Descarga] (https://github.com/AnkitKumar111/Android_Assignment17.2/tree/master/sample/archive/master.zip)
1. GitHub: Navegar 2. GitHub: Navegar
2. GitHub Creador original: @AnkitKumar111

Android IntentService

public abstract class IntentService
extends Service
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.app.Service
↳ android.app.IntentService

IntentService es una clase base para Servicios que manejan peticiones asíncronas (expresadas como Intents) bajo demanda. Los clientes envían las peticiones a través de llamadas a startService(Intent); el servicio se inicia cuando es necesario, maneja cada Intent por turnos usando un thread de trabajador, y se detiene cuando se queda sin trabajo.

Este patrón de "procesador de cola de trabajo" se utiliza habitualmente para descargar tareas del "hilo" principal de una aplicación. La clase IntentService existe para simplificar este patrón y encargarse de la mecánica. Para utilizarla, extiende IntentService e implementa onHandleIntent(Intent). El IntentService recibirá los Intents, lanzará un thread trabajador, y detendrá el service según corresponda.

Todas las peticiones se gestionan en un único thread de trabajo -pueden tardar tanto como sea necesario (y no bloquearán el bucle principal de la aplicación), pero sólo se procesará una petición cada vez.

Categorizado en:

Etiquetado en: