1. Code
  2. Mobile Development
  3. Android Development

Fundamentos de Android: Conceptos básicos de IntentService

Scroll to top
This post is part of a series called Android Fundamentals.
Android Fundamentals: Database Dates and Sorting

Spanish (Español) translation by steven (you can also view the original English article)

Hoy nos gustaría hacer un recorrido rápido por uno de los tipos de servicios menos conocidos pero muy útiles que quizás desees utilizar: IntentService.

IntentService (android.app.IntentService) es un tipo simple de servicio que se puede usar para manejar el trabajo asincrónico fuera del hilo principal mediante solicitudes de intención. Cada intent se agrega a la cola de IntentService y se maneja secuencialmente.

IntentService es una de las formas más sencillas de descargar "fragmentos" del procesamiento del subproceso de la interfaz de usuario de tu aplicación y en una cola de trabajo remota. No es necesario iniciar una AsyncTask y administrarla cada vez que tengas más procesamiento. En su lugar, simplemente define tu propio servicio, empaqueta una intención con los datos apropiados que deseas enviar para su procesamiento e inicia el servicio. Puedes enviar datos a la aplicación simplemente transmitiendo el resultado como un objeto Intent y usando un receptor de transmisión para capturar el resultado y usarlo dentro de la aplicación.

Paso 0: Comenzando

Hemos proporcionado una aplicación de muestra que ilustra la diferencia entre intentar realizar el procesamiento en el subproceso principal de la interfaz de usuario (un no-no para la capacidad de respuesta de la aplicación) y descargar ese mismo procesamiento a un IntentService. El código se puede descargar a través del enlace de descarga de código en la parte superior de este tutorial.

Paso 1: Definición del procesamiento de mensajes

En primer lugar, es importante comprender cuándo y por qué utilizar los servicios en general. Una buena razón para usar IntentService es cuando tienes trabajo que debe ocurrir fuera del hilo principal para mantener la aplicación adaptable y eficiente. Otra razón es cuando puedes tener múltiples solicitudes de procesamiento, y es necesario ponerlas en cola y manejarlas sobre la marcha.

Entonces, digamos que tenemos una aplicación que necesita hacer algún "procesamiento". Queríamos algo simple, así que básicamente definiremos el procesamiento en este caso como tomar un parámetro de cadena, hacerle "cosas" y devolver el resultado de la cadena. Para mantener este tutorial simple, lo que haremos es dormir durante 30 segundos, pretendiendo hacer algo útil. En realidad, las "cosas" probablemente serían el procesamiento de imágenes, la conexión a una red o alguna otra operación de bloqueo.

Por lo tanto, si todo el "procesamiento" ocurriera dentro de la aplicación principal, es posible que tengas un control EditText para tomar la entrada de mensajes y un control TextView para dividir el resultado. Puedes colocar este código en un controlador de botón para activar el procesamiento. El código en el controlador de clic de botón dentro de la clase Actividad de la aplicación se vería así:

1
EditText input = (EditText) findViewById(R.id.txt_input);
2
String strInputMsg = input.getText().toString();
3
4
SystemClock.sleep(30000); // 30 seconds, pretend to do work

5
6
TextView result = (TextView) findViewById(R.id.txt_result);
7
result.setText(strInputMsg + " " + DateFormat.format("MM/dd/yy h:mmaa", System.currentTimeMillis()));

Los resultados no son ideales de ninguna manera. Tan pronto como el usuario hace clic en el botón, toda la aplicación deja de responder. La pantalla está congelada, el usuario no puede continuar con su negocio, agregar mensajes nuevos. Básicamente, el usuario tiene que esperar a que finalice el procesamiento antes de poder hacer algo.

Paso 2: Implementar un IntentService

Preferimos que nuestro procesamiento no interfiera con la aplicación. También nos gustaría poder agregar fácilmente múltiples solicitudes de proceso de mensajes. ¡Este es el momento perfecto para utilizar IntentService! Así que implementemos uno.

Crea otro archivo de clase en tu proyecto y agrega códigos auxiliares para los métodos que necesitas implementar. Debes agregar un constructor con el nombre de tu nuevo servicio. Deberás implementar solo otro método llamado onHandleIntent(). Este método es donde ocurre tu procesamiento. Todos los datos necesarios para cada solicitud de procesamiento se pueden empaquetar en los extras de la intención, así (importaciones, comentarios, manejo de excepciones eliminado para mayor claridad del código, consulta el código fuente completo para obtener más detalles):

1
public class SimpleIntentService extends IntentService {
2
    public static final String PARAM_IN_MSG = "imsg";
3
    public static final String PARAM_OUT_MSG = "omsg";
4
5
    public SimpleIntentService() {
6
        super("SimpleIntentService");
7
    }
8
9
    @Override
10
    protected void onHandleIntent(Intent intent) {
11
12
        String msg = intent.getStringExtra(PARAM_IN_MSG);
13
        SystemClock.sleep(30000); // 30 seconds

14
        String resultTxt = msg + " "
15
            + DateFormat.format("MM/dd/yy h:mmaa", System.currentTimeMillis());
16
    }
17
}

Ten en cuenta que también definimos los parámetros adicionales de intención para los datos de intención entrantes y salientes. Usamos el PARAM_IN_MSG extra para los datos del mensaje entrante. Pronto usaremos el extra PARAM_OUT_MSG para enviar los resultados a la aplicación principal.

Paso 3: Inicia el servicio desde la actividad de tu aplicación

A continuación, debes iniciar el servicio desde la actividad de tu aplicación. Agrega un segundo control de botón que, en lugar de realizar el procesamiento en el hilo principal, delega el procesamiento a tu nuevo servicio. El nuevo controlador de botones se ve así:

1
EditText input = (EditText) findViewById(R.id.txt_input);
2
String strInputMsg = input.getText().toString();
3
Intent msgIntent = new Intent(this, SimpleIntentService.class);
4
msgIntent.putExtra(SimpleIntentService.PARAM_IN_MSG, strInputMsg);
5
startService(msgIntent);

El código para el método de procesamiento del servicio es bastante sencillo. Primero, se genera una instancia de Intent y cualquier dato (como el texto del mensaje) se empaqueta en el intent utilizando los extras. Finalmente, IntentService se inicia con una llamada a startService().

El servicio toma el control a partir de aquí, detecta cada solicitud de intención, la procesa y se apaga cuando todo está listo. La interfaz de usuario principal permanece adaptable durante todo el procesamiento, lo que permite que el usuario continúe interactuando con la aplicación. El usuario puede ingresar varios mensajes, presionar el botón una y otra vez, y cada solicitud se agrega a la cola de trabajo del servicio y se maneja. Considerándolo todo, una mejor solución.

Pero aún no hemos terminado.

Paso 4: Definir el receptor de transmisión

Tu IntentService ahora puede hacer su trabajo de procesamiento, pero lo necesitamos para informar la actividad de la aplicación principal cuando se procesa cada solicitud para que la interfaz de usuario se pueda actualizar. Esto solo importa cuando la actividad se está ejecutando, por lo que usaremos un modelo simple de transmisor/receptor de transmisión.

Comencemos por definir una subclase BroadcastReceiver dentro de la actividad principal.

1
public class ResponseReceiver extends BroadcastReceiver {
2
   public static final String ACTION_RESP =    
3
      "com.mamlambo.intent.action.MESSAGE_PROCESSED";
4
   
5
   @Override
6
    public void onReceive(Context context, Intent intent) {
7
       TextView result = (TextView) findViewById(R.id.txt_result);
8
       String text = intent.getStringExtra(SimpleIntentService.PARAM_OUT_MSG);
9
       result.setText(text);
10
    }
11
}

El método onReceive() hace todo el trabajo. Actualiza el control TextView de la actividad en función de los datos adicionales de la intención empaquetados en el resultado entrante.

Nota: Si estabas actualizando una base de datos o preferencias compartidas, existen formas alternativas para que la interfaz de usuario reciba estos cambios. En estos casos, la sobrecarga de un receptor de radiodifusión no sería necesaria.

Paso 5: Transmite el resultado

A continuación, debes enviar una transmisión desde el método onHandleIntent() de la clase IntentService después de que se complete el procesamiento y haya un resultado disponible, como este:

1
// processing done here….

2
Intent broadcastIntent = new Intent();
3
broadcastIntent.setAction(ResponseReceiver.ACTION_RESP);
4
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
5
broadcastIntent.putExtra(PARAM_OUT_MSG, resultTxt);
6
sendBroadcast(broadcastIntent);

Para enviar el resultado de regreso a la aplicación principal, empaquetamos otro intento, pegamos los datos del resultado como extra y lo devolvemos usando el método sendBroadcast().

Paso 7: Registrar el receptor de transmisión

Finalmente, debes crear una instancia y registrar el receptor que has definido en tu actividad. Registra el receptor en el método onCreate() con el filtro de intención apropiado para capturar la intención de resultado específica que se envía desde IntentService.

1
public class IntentServiceBasicsActivity extends Activity {    
2
    private ResponseReceiver receiver;
3
    
4
    @Override
5
    public void onCreate(Bundle savedInstanceState) {
6
        super.onCreate(savedInstanceState);
7
        setContentView(R.layout.main);
8
        
9
        IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
10
        filter.addCategory(Intent.CATEGORY_DEFAULT);
11
        receiver = new ResponseReceiver();
12
        registerReceiver(receiver, filter);
13
    }
14
}

El resultado: cada vez que IntentService termina de procesar una solicitud, lanza una transmisión con el resultado. La actividad principal puede escuchar la transmisión, y el método onReceive() del receptor de transmisión hace el resto actualizando la interfaz de usuario en consecuencia. No olvides también cancelar el registro del receptor en el momento adecuado (se recomienda onPause()).

Conclusión

Descargar el trabajo del subproceso principal de la interfaz de usuario de una aplicación a una cola de trabajo en un IntentService es una forma fácil y eficiente de procesar múltiples solicitudes. Hacerlo mantiene tu aplicación principal adaptable y a tus usuarios felices. Para muchos propósitos, usar un IntentService puede ser más fácil y deseable que un AsyncTask, que se limita a una sola ejecución, o un Thread, que tiene más sobrecarga de codificación.

Sobre los autores

Los desarrolladores de dispositivos móviles Lauren Darcey y Shane Conder han sido coautores de varios libros sobre el desarrollo de Android: un libro de programación en profundidad titulado Desarrollo de aplicaciones inalámbricas de Android, Segunda edición y Sams - Aprende tú mismo: Desarrollo de aplicaciones Android en 24 horas, segunda edición. Cuando no están escribiendo, dedican su tiempo a desarrollar software móvil en su empresa y a brindar servicios de consultoría. Se les puede contactar por correo electrónico a androidwirelessdev+mt@gmail.com, a través de su blog en androidbook.blogspot.com y en Twitter @androidwireless.

¿Necesitas más ayuda para escribir aplicaciones de Android? ¡Consulta nuestros últimos libros y recursos!

También hay una gran selección de plantillas de aplicaciones de Android disponibles en Envato Market para ayudarte a comenzar con tus proyectos de desarrollo de Android.