Android Tutorial Service Modules

This is an old tutorial. Most of the information here is no longer correct.



Basic4android v1.2 adds support for Service modules.
Service modules play an important role in the application and process life cycle.
Start with this tutorial if you haven't read it before: Android Process and activities life cycle
Code written in an activity module is paused once the activity is not visible.
So by only using activities it is not possible to run any code while your application is not visible.
Services life cycle is (almost) not affected by the current visible activity. This allows you to run tasks in the background.
Services usually use the status bar notifications to interact with the user. Services do not have any other visible elements. Services also cannot show any dialog (except of toast messages).
Note that when an error occurs in a service code you will not see the "Do you want to continue?" dialog. Android's regular "Process has crashed" message will appear instead.

Before delving into the details I would like to say that using services is simpler than it may first sound. In fact for many tasks it is easier to work with a service instead of an activity as a service is not paused and resumed all the time and services are not recreated when the user rotates the screen. There is nothing special with code written in service.
Code in a service module runs in the same process and the same thread as all other code.

It is important to understand how Android chooses which process to kill when it is low on memory (a new process will later be created as needed).
A process can be in one of the three following states:
- Foreground - The user currently sees one of the process activities.
- Background - None of the activities of the process are visible, however there is a started service.
- Paused - There are no visible activities and no started services.

Paused processes are the first to be killed when needed. If there is still not enough memory, background processes will be killed.
Foreground processes will usually not be killed.

As you will soon see a service can also bring a process to the foreground.

Adding a service module is done by choosing Project - Add New Module - Service Module.
The template for new services is:
B4X:
Sub Process_Globals

End Sub

Sub Service_Create

End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Sub Service_Destroy

End Sub
Sub Process_Globals is the place to declare the service global variables. There is no other Globals sub like in Activity as Service doesn't support Activity objects.
Sub process globals should only be used to declare variables. It should not run any other code as it might fail. This is true for other modules as well.
Note that Process_Global variables are kept as long as the process runs and are accessible from other modules.

Sub Service_Create is called when the service is first started. This is the place to initialize and set the process global variables. Once a service is started it stays alive until you call StopService or until the whole process is destroyed.
Sub Service_Start is called each time you call StartService (or StartServiceAt). When this subs runs the process is moved to the foreground state. Which means that the OS will not kill your process until this sub finishes running. If you want to run some code every couple of minutes / hours you should schedule the next task with StartServiceAt inside this sub.

Sub Service_Destroy is called when you call StopService. The service will not be running after this sub until you call StartService again (which will run Sub Service_Create followed by Sub Service_Start).
Service use cases

As I see it there are four main use cases for services.
- Separating UI code with "business" or logic code. Writing the non-UI code in a service is easier than implementing it inside an Activity module as the service is not paused and resumed and it is usually will not be recreated (like an Activity).
You can call StartService during Activity_Create and from now on work with the service module.
A good design is to make the activity fetch the required data from the service in Sub Activity_Resume. The activity can fetch data stored in a process global variable or it can call a service Sub with CallSub method.

- Running a long operation. For example downloading a large file from the internet. In this case you can call Service.StartForeground (from the service module). This will move your activity to the foreground state and will make sure that the OS doesn't kill it. Make sure to eventually call Service.StopForeground.

- Scheduling a repeating task. By calling StartServiceAt you can schedule your service to run at a specific time. You can call StartServiceAt in Sub Service_Start to schedule the next time and create a repeating task (for example a task that checks for updates every couple of minutes).

- Run a service after boot. By setting the #StartAtBoot attribute to True, our service will run after boot is completed.
Notifications

Status bar notifications can be displayed by activities and services.
Usually services use notifications to interact with the user. The notification displays an icon in the status bar. When the user pulls the status bar they see the notification message.

Example of a notification (using the default icon):

notification_1.png



notification_2.png


The user can press on the message, which will open an activity as configured by the Notification object.

The notification icon is an image file which you should manually put in the following folder: <project folder>\Object\res\drawable.
Accessing other modules

Process global objects are public and can be accessed from other modules.
Using CallSub method you can also call a sub in a different module.
It is however limited to non-paused modules. This means that one activity can never access a sub of a different activity as there could only be one running activity.
However an activity can access a running service and a service can access a running activity.
Note that if the target component is paused then an empty string returns.
No exception is thrown.
You can use IsPause to check if the target module is paused.

For example if a service has downloaded some new information it can call:
B4X:
CallSub(Main, "RefreshData")
If the Main activity is running it will fetch the data from the service process global variables and will update the display.
It is also possible to pass the new information to the activity sub. However it is better to keep the information as a process global variable. This allows the activity to call RefreshData whenever it want and fetch the information (as the activity might be paused when the new information arrived).

Note that it is not possible to use CallSub to access subs of a Code module.

Examples:
Downloading a file using a service module
Periodically checking Twitter feeds
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
I think that you are confusing public variables with global variables. While personally I use both some consider public variables to be problematic.

Global variables (instance variables) however are very important as they store the instance state.


I had left the programming about 10 years ago, when VB.Net was becoming more complex (but not for this reason).
Maybe that's why I do not remember the difference.

However, in B4A classes, you can declare public variables in the routine Class_Globals: as far as I know, they are public and global and I was talking about these (I do not see others :().

More or less this is the reason why I tend also to not use variables at the module level (eg Private in Class_Globals) to be used in the routines but I prefer to pass them as parameters to the routines; in this way, it will be easier to make them "autonomous" and perhaps use them in other modules or libraries.
 
Last edited:

Antony Danby

Member
Licensed User
Longtime User
As I was saying earlier it all boils down to what you need to expose to other classes ( your interface ). As Erel seems to be stating there seems to be a need to have the variables that we need to watch in the Service exposed as public as it looks like accessor methods ( getters and setters ) cannot be used. Is this interpretation correct ? If so, then that's just life, not everything is perfect in life I can deal with close to perfection and work around it. ;)
 

LucaMs

Expert
Licensed User
Longtime User
Some things are not clear to me, but I prefer not to elaborate and accept them as they are :D

In this case I am referring to a third thing, in addition to what I wrote in my previous post and the response of Erel, which covers references to Context etc. (although I suppose that they are related).

I can directly run a routine of a module from within an Activity:
eg
B4X:
Activity_Resume
MyCodeModule.RoutineX


but I can not if the routine is in a service:
B4X:
Activity_Resume
MyServiceModule.RoutineY


I must use CallSub:
B4X:
Activity_Resume
CallSub(MyServiceModule, "RoutineY")



(different speech for global public variables in my previous post, for which Erel has lost hope that I can understand :p)
 

Straker

Active Member
Licensed User
Longtime User
Luca, if you think a bit (ok, heavy task;)) it's obvious.
A service is something separated from the activity. The activity may finish but the service is still running. There is not a real 'link' between them, so you need the callSub statement.
Code modules instead are just addiction all code placed in another file just for have a cleaner code and reusability of the subs.
 

LucaMs

Expert
Licensed User
Longtime User
Luca, if you think a bit (ok, heavy task;)) it's obvious.
A service is something separated from the activity. The activity may finish but the service is still running. There is not a real 'link' between them, so you need the callSub statement.
Code modules instead are just addiction all code placed in another file just for have a cleaner code and reusability of the subs.


You're right, often i don't want to think to much, because I need to preserve my beauty :D

In this case, however, I should also read (two labors at the same time? I risk of becoming Brunetta! :confused:), because I do not remember that a service will remain active after the death of an activity.[EDIT: death of process, because it is clear that you can "finish" an Activity without close your app]

If it were so, means it that they run in separate threads? (Ok, I will read).

Since you do not have these problems (in the sense that you think too much and you lose in a beauty contest against the opponent above mentioned :D), would you be kind and clarify my ideas about #140 #141?


Thank you, Cap.
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
If it were so, means it that they run in separate threads? (Ok, I will read).

(I'm reading)
From post #1:
"Code in a service module runs in the same process and the same thread as all other code."


From Android Process and activities life cycle post #1:
"A process has one main thread which is also named the UI thread which lives as long as the process lives. A process can also have more threads which are useful for background tasks."
 
Last edited:

Straker

Active Member
Licensed User
Longtime User
(I'm reading)
From post #1:
"Code in a service module runs in the same process and the same thread as all other code."

Yes, it's true. Is in the same thread but they are two different processes.
For example, you can have and activity that performs some task and a service providing data for that task.
You can call Activity.Finish and the service is till running (if not ended otherwise).

Better example: an app that every tot minutes retrieves data from a webserver with a service. If data is present it will show the data in the Activity's UI. You can kill the activity (I mean completely close, destroy, swipe away from 'task manager') but every tot minutes the service fetch the data (I assume the service will schedule itself every tot minutes with StartServiceAt + time). The service can check if the main activity is in foreground with IsPaused(activityname). If is in pause (or destroyed) the service can pop up a notification (you got a message!) and also prepare the data for activity with a callSubDelayed, and when the user click on the notification the activity is restarted and callSubDelayed can send the data. If is not paused / destroyed, the service just send the data to the activity with a normal callSub.

If you want to play with services, and see what happens if you kill the app but not the service, I posted a simple demo of a socket which every 3 minutes retrieves data from a VB66 socket server (source included) and if the activity is in foreground, shows the data, else performs a notifications. I also added a Text to Speech class. http://www.b4x.com/android/forum/threads/45017/#content
 

Straker

Active Member
Licensed User
Longtime User
Maybe I'm wrong, but I think that the classes should not contain global variables. It is better pass the value using the properties.

There is a diffference between public and global variables.
A public variable is a variable that you can access everywhere. Public variables is technically forbidden inside a class, because a class should be 'closed' and every value or data the class needs must be passed through a property or method of the class.

A global variable is something you can access everywhere inside a module.
Speaking of class, in VB6 the global variables were the 'mvar...', variables the the class can access everywhere inside the class itself, but which are not exposed outside a class (or exposed only through a Get or Set)

Speaking of class, to be honest, I don't agree with the fact that the variables declared in class_Globals are automatically global, those variables should be automatically Private, not Global (but in B4a all the variables are global if you don't declare them as private, so there is a logic). For example if you have a class Person with a variable Age you can write Person.Age and reference directly the variable. I prefer to mantain all the class variables Private and reference them with Set and Get...
 

Straker

Active Member
Licensed User
Longtime User

I know that there is only one process going on. But you can think the service as a separate process because you can terminate the activity and leave the service running.
 

Straker

Active Member
Licensed User
Longtime User
You're making more confusion than me: an Activity is not the process, it is not listed in the task manager.

Ok, probably I'm missing some correct word. When you write an App, even as simple as Hello World (Just a msgbox in the Activity_Create), how do you call it? For me is an activity...
 

LucaMs

Expert
Licensed User
Longtime User
Speaking of class, in VB6 the global variables were the 'mvar...', variables the the class can access everywhere inside the class itself, but which are not exposed outside a class (or exposed only through a Get or Set)

I call them "Module Variables", not Public Variables.

In fact, in a class you can define a Private variable in the Class_Globals and it will be accessible to all routines of the class.

If you define that variable as Public it will be accessible outside the object! So, these are [EDIT: the only] Global variables, I think.


[P.S. I call them "module variables"? What m in mVar means? Module variables :D]
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Ok, probably I'm missing some correct word. When you write an App, even as simple as Hello World (Just a msgbox in the Activity_Create), how do you call it? For me is an activity...

Now I can't, but I'll try this:

Just one Activity (Main!) and a Service.
Run and ExitApplication in the Activity_Resume (after started the Service)

Do you think the Service will be still alive?
 

Straker

Active Member
Licensed User
Longtime User
Last edited:

Straker

Active Member
Licensed User
Longtime User
Ok, the process restarts... so also the Main Activity?

Have you experienced this in your test?

The main activity doesn't restart. It has been finished.
In my test I can leave the service running and kill the activity (activity.finish OR ExitApplication, and also "swipe out" from taskmanager). The service is still running (of course). If the service pops up a notification, from it the O.S. can re-create the activity.
If you want completely end the application you need first to StopService and CancelScheduledService (so the service will stop and it will not be recreated), then you can finish the activity. Now the app is really "dead".

Anyway, I still don't grab the differences between Activity.Finish and ExitApplication...:( Can someone help and explain?
 

LucaMs

Expert
Licensed User
Longtime User
Anyway, I still don't grab the differences between Activity.Finish and ExitApplication...:( Can someone help and explain?

Activity.Finish closes the Activity, not the App!

ExitApplication closes the App, but, as wrote in the post you linked, if there is an active service, the process restarts. In this case, if you put a Log in the Main Activity, you could be sure if Main restarts or not (i'm not so sure, i think that Main restarts)
 

Straker

Active Member
Licensed User
Longtime User
Activity.Finish closes the Activity, not the App!

ExitApplication closes the App, but, as wrote in the post you linked, if there is an active service, the process restarts. In this case, if you put a Log in the Main Activity, you could be sure if Main restarts or not (i'm not so sure, i think that Main restarts)

You cannot put a log. When the activity finishes the debugger will disconnect and you don't have the logs.
I placed a msgbox in Create and Resume. When the service restart they are not fired up. The are fired only when the activity comes in foreground (for example when 'revived' by a click on a notification...)
 
Top