Podemos consultar una guía de los Servicios en los foros de B4A.
http://www.basic4ppc.com/forum/basic4android-getting-started-tutorials/7542-service-modules.html
Servicios.
Un servicio es algo así como un programa que se está ejecutando en segundo plano (background).
Los programas funcionan mientras son visibles (Foreground), si estamos utilizando un programa y lanzamos otro en pantalla, el programa anterior se para (Paused), y no sigue ejecutándose.
Cuando volvemos al programa anterior volvemos a la Subrutina Activity_Resume.
Si una aplicación está Paused y el Android necesita memoria para otras aplicaciones, apagará la aplicación Paused.
Los servicios pueden estar ejecutándose aunque no sean visibles (Background). Los servicios no son interactivos, no podemos escribir/leer información del servicio, solo permite el ToastMessage. Los servicios no se apagan hasta que el usuario u otra aplicación le envía un StopService.
Imagínate que hacemos un programa con contador automático, cuando lo ejecutamos va contando 1, 2, 3, 4...
Si ahora abrimos otra aplicación, el programa anterior entra en Paused y no sigue contando.
En cambio con un Servicio el contador seguiría contando aunque entremos en otro programa.
- IMPORTANTE: el código válido se encuentra al final de esta pagina, en SERVICIOS. Reloj.
_____________
- Proceso.
Vamos a crear un proyecto.
Mediante el Designer creamos dos Botones (Arrancar y Parar) y un Label1 lo guardamos con el nombre de Layout.
Arrancar.Text = "Arrancar"
Parar.Text = "Parar"
Copiamos y pegamos el siguiente código...
Activity Main |
'Activity module
Sub Process_Globals
' Juan Antonio Villalpando
' juana1991@yahoo.com
End Sub
Sub Globals
Dim Arrancar, Parar As Button
Dim Label1 As Label
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Layout")
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Parar_Click
CancelScheduledService(servicio) ' Para el StartServiceAt
StopService(servicio)
End Sub
Sub Arrancar_Click
StartService(servicio)
End Sub
Sub muestra
' Utilizo la variable Cuenta creada en el Servicio
Label1.Text= servicio.cuenta
End Sub
|
|
Ahora vamos a crear el servicio.
Para crear un servicio vamos a:
Project - Add New Module - Service Module.
Creamos un servicio y lo llamamos servicio.
Fíjate que se ven dos pestañas:
Main y servicio
Puedes pasar de uno a otro pulsando en su pestaña. |
|
Copiamos y pegamos este código en servicio...
servicio |
'Service module
Sub Process_Globals
Dim cuenta As Int
cuenta = 0
Dim N As Notification
End Sub
Sub Service_Create
' Establecimiento de las Propiedades de Notificación
N.Initialize
N.Icon = "icon"
N.Sound = False
N.Vibrate = False
N.Light = False
N.OnGoingEvent=True
N.SetInfo("Contador", cuenta, Main)
N.Notify(1)
End Sub
Sub Service_Start (StartingIntent As Intent)
cuenta = cuenta + 1
' If cuenta = 20 Then ToastMessageShow("He llegado a 20", True)
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)
CallSub(Main, "muestra")
End Sub
Sub Service_Destroy
N.Cancel(1)
End Sub
|
Pulsamos el Botón de Arrancar y comenzará a arrancar el servicio. Comenzará el servicio y la cuenta.
Si vas al icono de Aplicaciones del Android, lanzas otra aplicación cualquiera y luego vuelves al programa de servicio que estamos haciendo, verás como el contador ha evolucionado y sigue mostrando las cuentas.
Eso es porque el servicio ha estado sumando la variable cuenta.
Así que un servicio es un programa que está funcionando desde que lo lanzamos hasta que lo paremos, aunque salgamos de la aplicación que lo ha lanzado.
_____________
- Comentarios:
- Esta es la Subrutina que muestra el valor, fíjate como toma la variable del servicio: servicio.cuenta
Sub muestra ' Utilizo la variable Cuenta creada en el Servicio
Label1.Text= servicio.cuenta
End Sub
- Estas dos líneas hacen que el servicio entre en funcionamiento cada cierto tiempo, en este caso 1 segundo.
Y que vaya a la subrutina "muestra" del Main.
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)
CallSub(Main, "muestra")
- Vamos a escribir: Activity.Finish, en la Subrutina Arrancar.
Sub Arrancar_Click
StartService(servicio)
Activity.Finish
End Sub
Observa que cuando arrancas, comienza el servicio pero Finaliza la aplicación que lo ha lanzado.
Sin embargo si vamos al panel de Aplicaciones del Android y pulsamos en el programa, observamos que el contador sigue contando, es decir, el servicio sigue actuando aunque el programa lanzador no esté en pantalla.
- En el servicio podemos poner condiciones, por ejemplo si llega a 20 lanza un mensaje:
' If cuenta = 20 Then ToastMessageShow("He llegado a 20", True)
- Dependiendo del código que estemos trabajando, el servicio puede que deba ejecutarse una vez y estar haciendo su labor hasta que la termine, o podemos ejecutarlo cada cierto tiempo, para ello utilizamos esta línea:
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)
En este caso se repetirá el código del servicio cada 1 segundo.
En general no hace falta arrancar el servicio cada cierto tiempo con StartServiceAt, ya que una vez arrancado el Servicio este está continuamente ejecutándose hasta que lo paremos mediante StopService
- Podemos parar un servicio desde los paneles del Android, concretamente desde Configuración / Aplicaciones:
Administrar Aplicaciones
Servicios en ejecución
En nuestro caso nuestro servicio se ha convertido en un Demonio (daemon), se decir que lo paramos pero debido a:
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)
renace en un segundo.
En el tutorial: 37.- Parar programas, he puesto otra forma de pararlo. También se puede parar desde el Shell de Linux en modo root.
- Si queremos iniciar el servicio en el arranque, en el módulo del Servicio ponemos:
#Region Module Attributes
#StartAtBoot: True
#End Region
_____________
Es decir, podemos realizar un servicio que funcione en segundo plano (background) que esté vigilante de cualquier evento, por ejemplo que se reciba un SMS, que estemos en cierto lugar geográfico detectado mediante GPS, que cuando la batería llegue a determinado nivel salte una alarma, que sea determinada hora, que esté bajando algún archivo de gran tamaño de internet mientras estamos haciendo otra cosa, que cuando arranque un programe se pare otro,...
- Servicio con el twitter.
Uno de los defectos de los servicios es que si están funcionando continuamente están gastando batería.
Por eso nos recomiendan en los manuales que apagemos la función GPS, WiFi,... de nuestro móvil cuando no las estamos utilizando.
Para consultar si un servicio está funcionando podemos utilizar el siguiente código:
Sub Activity_Create(FirstTime As Boolean)
If IsPaused(servicio) = False Then
ToastMessageShow("Servicio funcionando ",False)
Activity.Finish
Return True
End If
StartService(servicio)
Activity.Finish
End Sub
____________________________________________________________________________
Un servicio que está funcionando en segundo plano (background), lo podemos pasar a primer plano mediante la instrucción:
StartForeground
____________________________________________________________________________
Aquí tenemos un ejemplo más completo:
http://www.basic4ppc.com/forum/basic4android-getting-started-tutorials/7542-service-modules-6.html
_____________
- CallSubDelayed2
Es importante conocer la función CallSubDelayed2, se utiliza para pasar variables entre Activity y Servicios (no vale para intercambiar variables entre módulos de código).
Normalmente estas variables se pasaban haciéndolas globales, pero con esta función es más fácil.
Cuando una Activity llama a un Servicio mediante el CallSubDelayed2, no hace falta poner StartActivity ni StartService en el código de llamada.
En los foros, hay un ejemplo muy clarificador llamado TwoActivities.zip, en donde un Activity llama a otro para que pesente un ListView, cuando pulsamos en un elemente del ListView, su valor para al primer Activity, el Main.
Existe tres tipos de CallSubDelayed.
CallSubDelayed (Component As Object , Sub As String )
CallSubDelayed2 (Component As Object , Sub As String , Argument As Object )
CallSubDelayed3 (Component As Object , Sub As String , Argument1 As Object , Argument2 As Object )
_____________
- Un bonito ejemplo de Servicio. Mostrar número de llamada entrante.
Lo puedes encontrar al final de esta página del foro oficial. Concretamente se llama detectincomingph.zip
Es un Servicio basado en la librería Phone, PE_PhoneStateChanged (State As String, IncomingNumber As String, Intent As Intent)
Lo que hace es mostrar el número de la llamada entrante.
Fíjate como arranca y para el Servicio. Y como sale del programa mediante la tecla de Atrás.
_______________________________
_______________________________
_______________________________
_______________________________
- SERVICIOS. Reloj. Este código es más funcional.
- Creamos un Layout, con dos Botones y un Label. A los Botones los llamamos Iniciar y Parar.
- En el Main, copiamos este código.
- En la parte de Administrador de Librerías, marcamos Audio.
Main |
#Region Project Attributes
#ApplicationLabel: B4A Reloj
#VersionCode: 1
#VersionName:
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: portrait
#CanInstallToExternalStorage: False
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
#BridgeLogger: true
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim b As Beeper
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim Iniciar, Parar As Button
Dim Label1 As Label
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Layout")
b.Initialize(300, 500) '300 milliseconds, 500 hz
End Sub
Sub Activity_Resume
StartService(Tracker)
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Iniciar_Click
StartService(Tracker)
b.Beep
End Sub
Sub Parar_Click
CancelScheduledService(Tracker) ' Para el StartServiceAt
StopService(Tracker)
End Sub
Sub muestra
' Utilizo la variable Cuenta creada en el Servicio
Label1.Text= Tracker.cuenta
End Sub
|
- Vamos a Proyecto / Añadir nuevo Módulo / Módulo de Servicio.
- Lo llamamos Tracker y copiamos el siguiente código:
Tracker |
#Region Service Attributes
#StartAtBoot: True
#End Region
Sub Process_Globals
Private nid As Int = 1
Dim cuenta As Int = 0
Dim Timer1 As Timer
Private Tracking As Boolean
Private lock As PhoneWakeState
Dim b As Beeper
End Sub
Sub Service_Create
Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER 'we are handling it ourselves
Timer1.Initialize("Timer1", 1000) ' 1000 = 1 segundo
Timer1.Enabled = True
lock.PartialLock
b.Initialize(300, 1000) '300 milliseconds, 500 hz
End Sub
Sub Service_Start (StartingIntent As Intent)
Service.StartForeground(nid, CreateNotification("..."))
StartServiceAt(Me, DateTime.Now + 30 * DateTime.TicksPerMinute, True)
Track
End Sub
Public Sub Track
If Tracking Then Return
If Starter.rp.Check(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION) = False Then
Log("No permission")
Return
End If
Tracking = True
End Sub
Sub Timer1_Tick
' Cada vez que pasan 1000 milisegundos
cuenta = cuenta + 1
Dim n As Notification = CreateNotification(cuenta)
n.Notify(nid)
CallSub(Main, "muestra")
If cuenta Mod 4 = 0 Then
b.Beep
End If
End Sub
Sub CreateNotification (Body As String) As Notification
Dim notification As Notification
notification.Initialize2(notification.IMPORTANCE_LOW)
notification.Icon = "icon"
notification.SetInfo("Reloj", Body, Main)
Return notification
End Sub
Sub Service_Destroy
Tracking = False
lock.ReleasePartialLock
End Sub
|
________________________________