Android Tutorial Receivers and Services in 2023+

In the early days of Android services were simple to use and powerful. They allowed doing all kinds of things in the backgrounds with very few restrictions. That's not the case with newer versions of Android.
With a few exceptions (that aren't 100% reliable), the only use case for services is to let the app continue to do its job while it moves to the background - for example a music player app or navigation app.

B4A v12.2 includes a new type of module named Receiver or the Java term static Broadcast Receiver. Receivers "listen" to intents and are started when a relevant intent is received.
The default code is:
B4X:
Sub Process_Globals
  
End Sub

'Called when an intent is received.
'Do not assume that anything else, including the starter service, has run before this method.
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
  
End Sub
Receivers aren't actively listening to intents. It is the OS that is responsible for starting the process after a relevant intent was sent.
There are two types of intents that are deemed relevant:
1. Intents that explicitly target the receiver. For example, such intent is created when we schedule a receiver to start with StartReceiverAt.
2. Intents with actions that are defined in the manifest editor. For example, if we want to run something after boot:
B4X:
AddPermission(android.permission.RECEIVE_BOOT_COMPLETED)
AddReceiverText(MyReceiver, <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>)
A few use cases for receivers:
  • Handling push notifications
  • Scheduling receivers to run
  • Home screen widgets
  • Activity recognition
  • Run after boot
  • And more...
Q. Can receivers do everything that services can?

A. No. Receivers run for a short time. There is no similar feature to foreground services where a service can continue to run in the background indefinitely.

Q. I don't need new stuff. I will continue to use my beloved services for all of these use cases.

A. Good for you, but your app will crash on Android 12+ devices with this error when the process is started from the background:

Fatal Exception: java.lang.RuntimeException: Unable to start receiver b4a.example.starter$starter_BR: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service b4a.example/.starter

Notes
  • The starter service will not start before the receiver when a process starts from a receiver.
  • The CancelScheduledService keyword, which cancels services scheduled with StartServiceAt, also works with receivers scheduled with StartReceiverAt.
  • B4A services are actually made of a receiver + service. These automatic receivers are named <service>_BR. Not too important but you might encountered those in the past.
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
A service is normally unable to start an activity if there isn't already an activity in the foreground.
Can I start an Activity from a receiver?

Q. I don't need new stuff. I will continue to use my beloved services for all of these use cases.

A. Good for you
🤣
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
A service is normally unable to start an activity if there isn't already an activity in the foreground.
Can I start an Activity from a receiver?
It is the same as with services, only an app that requested the special "draw over apps" can start activities from the background:
 

hatzisn

Well-Known Member
Licensed User
Longtime User
I have this text in manifest in an app that checks when the bluetooth is connected or disconnected.

B4X:
AddReceiverText(sBT, <intent-filter>
<action android:name="android.bluetooth.device.action.ACL_CONNECTED"/>
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED"/>
</intent-filter>)

It directs the intent to a service which starts obviously and performs a PhoneWakeState object PartialLock and then it downloads relevant data according to the time of the day. My question is by moving the relevant code of the service to the receiver will it be the same? I mean since it runs for a short time will it be able to download the data with wait for (job) JobDone (job as HttpJob) or asynchronously with a seperate JobDone (job as HttpJob) sub if it takes some (enough) time for the data to be calculated and downloaded?
 

svanneste

Member
Licensed User
It doesn't say what happens if you're not finished after 10 seconds.
It seems the proper way is what we already do since a while : the receiver gets the intent then starts a service sending some data if required. The receiver is closed by the system. Our service finishes its task. And basta
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
About the ACL events:

1. This intent can be intercepted because it is listed here: https://developer.android.com/guide/components/broadcast-exceptions
2. @hatzisn you don't really have a choice. Your service will fail to start on Android 12+ devices.
3. Based on my tests you will have enough time to run your code and download the data.
Use Wait For as usual. There isn't any advantage for having a separate sub for the JobDone event.

”[...] the system expects you to finish with the broadcast very quickly (under 10 seconds)”

It doesn't say what happens if you're not finished after 10 seconds.
The OS can kill the process. As I wrote, based on my tests it will take more than 10 seconds for the OS to kill the process.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
It seems the proper way is what we already do since a while : the receiver gets the intent then starts a service sending some data if required. The receiver is closed by the system. Our service finishes its task. And basta
Nope. It will not work. With the exception of a few cases, you can no longer start services while the app is in the background.
 

techknight

Well-Known Member
Licensed User
Longtime User
Nope. It will not work. With the exception of a few cases, you can no longer start services while the app is in the background.

Which means a background service on boot is basically dead in the water now? that means I will need a way to start my overlay/display service on bootup for my digital signage platforms going forward when they start getting Android 12+
 

JohnC

Expert
Licensed User
Longtime User
Nope. It will not work. With the exception of a few cases, you can no longer start services while the app is in the background.
So the only way to run a service indefinately on Android 12+ devices (that can be in the Play Store) is to first display an activity and have the activity start a foreground service, then the activity can close and the Service will continue to run?
 
Last edited:

JohnC

Expert
Licensed User
Longtime User
Which means a background service on boot is basically dead in the water now? that means I will need a way to start my overlay/display service on bootup for my digital signage platforms going forward when they start getting Android 12+
If your app doesn't need to be downloaded from the Play store, then maybe you could set the Targetsdk to something less than Android 12 and have users sideload your app on their device.

This way even if the device has Android 12+ on it, it won't impose the new restrictions on the your app because it has a TargetSdk less then Android 12.
 

John Naylor

Active Member
Licensed User
Longtime User
@techknight , @JohnC - I too am confused. I cannot start my app automatically now? I have an app that pops up notifications (for my mum to take her medication at certain times). I've just upgraded to this beta, recompiled and my app is working as normal. It starts just the same as always on reboot.
 

aaronk

Well-Known Member
Licensed User
Longtime User
Am I reading it correct that Android 12+ devices are going down the path of iOS where you can't run the app in the background ?

Currently I am using a service to keep a TCP socket open in my app (24/7 and if it disconnects it will re-connect) as I want to get data from the socket and capture it in the app. I am assuming now on Android 12+ I can no longer do this since it will only run for a short time ?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I too am confused. I cannot start my app automatically now? I have an app that pops up notifications (for my mum to take her medication at certain times). I've just upgraded to this beta, recompiled and my app is working as normal. It starts just the same as always on reboot.
You can do it with receivers.

Am I reading it correct that Android 12+ devices are going down the path of iOS where you can't run the app in the background ?
Not exactly.

Currently I am using a service to keep a TCP socket open in my app (24/7 and if it disconnects it will re-connect) as I want to get data from the socket and capture it in the app. I am assuming now on Android 12+ I can no longer do this since it will only run for a short time ?
Consider switching to push notifications, however you can still keep your app running in the background by starting a foreground service while the app is in the foreground.
 

Ilya G.

Active Member
Licensed User
Longtime User
Nope. It will not work. With the exception of a few cases, you can no longer start services while the app is in the background.

Does this mean that it is desirable not to use the CallSub and CallSubDelayed from the receiver?
 

Ilya G.

Active Member
Licensed User
Longtime User
1. But service can CallSub and CallSubDelayed sub in receiver at any time?

2. Will there be changes here too?

1673523894606.png
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
but these receivers... exist since api 1, so i don't understand.
Receivers are not new in Android. The new thing is that services can no longer do what receivers can.

But service can CallSub and CallSubDelayed sub in receiver at any time?
CallSub only works if the target module is not paused. CallSubDelayed will work. It will start the receiver if needed.
Tip: don't implement your program logic in services or receivers. Do whatever you can in classes such as B4XPages classes.
 
Top