Spanish Cronometro simple [SOLUCIONADO]

carlos7000

Well-Known Member
Licensed User
Longtime User
Hola a todos. Estoy tratando de hacer un taxímetro simple. Para iniciar intente crear un cronometro simple. En otras palabras un programa que muestra el avance del tiempo en segundos.

El programa presenta 2 problemas:

  1. El primer problema es que el servicio encargado de contar los segundos se ejecuta al iniciar la aplicación. No sé si es normal o no debería suceder.
  2. El segundo problema es que el servicio se ejecuta muy lento.
El código que se supone hace que se ejecute cada segundo es:

B4X:
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)

Pero el servicio se ejecuta cada 2 o 3 segundos. A veces parece acelerar y a veces enlentecer.

El equipo en el que ejecuto el programa es un Huawei P9 Lite con procesador Cortex A53 de 4 núcleos y con una velocidad cada uno de 2 GHz, todas las aplicaciones cerradas y el modo de ahorro de energía deshabilitado. Ninguna aplicación ejecutándose en segundo plano. Todas las aplicaciones instaladas funcionan suavemente, con fluidez y sin problemas.

El código del modulo principal es:

B4X:
#Region  Project Attributes
    #ApplicationLabel: CronoSimple
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Dim Temporizador As Timer
    Dim Secs As Int
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.

    Private Label1 As Label
    Private ButtonStart As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("main")

    Temporizador.Initialize("Timer1", 1000)
    Temporizador.Enabled = True
End Sub

Sub Activity_Resume
    Secs = 0
    Label1.Text = "Secs: "
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Timer1_Tick
    Label1.Text = "Secs: " & Secs
End Sub

Sub ButtonStart_Click
    Try
        StartActivity(Starter)
    Catch
        Log(LastException)
    End Try
End Sub

El código del servicio es:

B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Dim Segundos As Int
End Sub

Sub Service_Create
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.

End Sub

Sub Service_Start (StartingIntent As Intent)
    StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)

    Segundos = Segundos + 1
    Main.Secs = Segundos
End Sub

Sub Service_TaskRemoved
    'This event will be raised when the user removes the app from the recent apps list.
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy

End Sub

Adjunto el proyecto en un .Zip para el que desee darle una mirada.

De antemano agradezco su valiosa ayuda.
 

Attachments

  • CronoSimple.zip
    7.9 KB · Views: 398
Last edited:

bgsoft

Well-Known Member
Licensed User
Longtime User
Hola Carlos:

Como decia Jack el destripador: "vayamos por partes" :D

Cosas que aunque no tengan que ver con el problema es interesante que las corrijas:

El temporizador inicializalo asi:
B4X:
  if FirstTime then
    Temporizador.Initialize("Timer1", 1000)
    Temporizador.Enabled = True
  end if
Si no, crearas nuevas instancias cada vez que entre en create, por ejemplo cuando gires el movil.

Por coherencia, cambia esto de:
B4X:
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)
Segundos = Segundos + 1
Main.Secs = Segundos
A:
B4X:
Segundos = Segundos + 1
Main.Secs = Segundos
StartServiceAt("", DateTime.Now + 1 * DateTime.TicksPerSecond, True)

Si tienes un módulo de servicio con la variable Segundos, que necesidad tienes de asignar otra en main asi :
B4X:
Main.Secs = Segundos
En main hazlo asi:
B4X:
Sub Timer1_Tick
Label1.Text = "Secs: " & Starter.Segundos
End Sub


El primer problema es que el servicio encargado de contar los segundos se ejecuta al iniciar la aplicación. No sé si es normal o no debería suceder.
Lo que te está ocurriendo, es que la primera vez que lo pusiste en marcha, como nunca paras el servicio, cuando entras sigue corriendo, o pones un botón para pararlo, o el boton de poner en marcha haces que a una pulsación pare y a otra lo ponga en marcha, y creas una etiqueta que te diga el estado del servicio.

El segundo problema es que el servicio se ejecuta muy lento.
Pero el servicio se ejecuta cada 2 o 3 segundos. A veces parece acelerar y a veces enlentecer.
Lógico, no puedes poner una llamada cada segundo por que te estas comiendo todos los recursos del sistema, y por eso te actualiza erroneamente. Los servicios a poder ser tienen que ser con llamadas largas, si no saturas el sistema.

Y ahora viene la pregunta del millón, si es un taxímetro, que necesidad tienes de crear un servicio?
Ese Taxímetro tendra que estar siempre en marcha y visible, y si por ejemplo quieres salir del Activity, que necesidad tienes de crear un servicio machacando los recursos si no estas visualizando nada?

Yo haria una cosa muy facil:
- Crea una variable global (long) en main (Sub Process_Globals)
- Cuando quieras "poner en marcha" tu taxímetrro a esta variable dale el valor en ticks de la hora actual (HoraInicio= DateTime.Now) y guardate la hora inicial en un fichero.
- El temporizador de main, emplealo, pero no para contar segundos, si no para visualizar el tiempo transcurrido (Hora Actual - Hora Inicio taxímetro)

Si sales con el taxímetro en marcha y vuelves a entrar, lee el fichero y asigna la Hora de Inicio del taxímetro a la variable global de Inicio de hora, si no existe el fichero (cuando pares el taxímetro borras el fichero) no haces nada al volver a entrar. Esto apenas consumirá recursos.

Saludos
 
Last edited:

carlos7000

Well-Known Member
Licensed User
Longtime User
Hola.

Soy muy novato en b4a. Por eso cometo muchos errores :(

- Acepto de buena gana todos los consejos.

Con respecto a la coherencia, La linea que define el nuevo llamado del servicio, ¿es mejor que este en la ultima linea de
Service_Start?

- Corregiré la inicialización del Timer según su sugerencia.

Esto:
B4X:
Main.Secs = Segundos

Lo hacia, porque no sabia como acceder desde el main al conteo que lleva el servicio.

Probare el código:

B4X:
Starter.Segundos

-Imaginaba que no era buena idea ejecutar un servicio cada segundo para una simple suma. Pero cree el servicio porque deseaba llevar el conteo aunque el usuario cambiara a otras aplicaciones. No se me había ocurrido lo del archivo. o_O

- El servicio aun lo necesitare, creo, porque cuando el usuario cambie a otra aplicación, aun el programa debe avisar cada vez que se recorra, por ejemplo 5 kms o cada 5 minutos, cual es el valor que lleva el taxímetro.

Voy a tratar de implementar todos sus comentarios.

Muchas gracias por su valiosa ayuda.
 

carlos7000

Well-Known Member
Licensed User
Longtime User
Hola.

Trate de leer la variable desde el Main pero no me funciona.

La variable en el servicio la decrare de dos formas:

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Public ValAPagar As Int
End Sub

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim ValAPagar As Int
End Sub

Pero en el Main al tratar de emplearla no aparece :confused:

Adjunto captura de pantalla.

Gracias por su ayuda.
 

Attachments

  • Captura de pantalla 2017-01-16 23.02.49.png
    Captura de pantalla 2017-01-16 23.02.49.png
    6.2 KB · Views: 391

bgsoft

Well-Known Member
Licensed User
Longtime User
Hola Carlos:

Antes de nada, ya se que soy mayor, pero si me sigues llamado de usted te dejo de contestar :D

Soy muy novato en b4a. Por eso cometo muchos errores :(
Nadie nace enseñado, y todos cada dia aprendemos algo, asi que no te preocupes, el foro está para preguntar lo que no sabemos, si todos supieramos mucho no tendria razon de ser el foro.


Con respecto a la coherencia, La linea que define el nuevo llamado del servicio, ¿es mejor que este en la ultima linea de
Service_Start?
Si, es mejor que la ultima llamada sea a StartServiceAt , va a funcionar igual, pero por coherencia es mejor que hagas primero todo lo que tienes que hacer y luego hagas esa llamada, tu código cuando lo tengas que modificar lo veras mas claro

- Corregiré la inicialización del Timer según su sugerencia.
Lo que te dije es que si no ponias la inicialización del timer asi:
B4X:
if FirstTime then
Temporizador.Initialize("Timer1", 1000)
Temporizador.Enabled = True
endif
Crearas nuevas instancias, o sea, vas a tener tantos timer (tu Temporizador) en marcha como veces entres en el create, y te volverás loco para averiguar ese error.

- El servicio aun lo necesitare, creo, porque cuando el usuario cambie a otra aplicación, aun el programa debe avisar cada vez que se recorra, por ejemplo 5 kms o cada 5 minutos, cual es el valor que lleva el taxímetro.
Pues pon el StartServiceAt a 5 minutos
B4X:
StartServiceAt("", DateTime.Now + ( 5 * DateTime.TicksPerMinute, True)
De esa forma no consumirás tantos recursos

Trate de leer la variable desde el Main pero no me funciona.

La variable en el servicio la decrare de dos formas:
Si te fijas en tu captura, te dice que es desconocido, pero no es desconocido por la variable, si no porque tu servicio lo llamaste Starter (ver en tu código del principio), y ahi lo llamas Start, por eso no lo encuentra.


Saludos
 
Top