Simplifying Background Tasks with Android Services & Broadcast Receivers
In-Depth Walkthrough on Enhancing Task Management and Event Handling in Android Apps
Services in Android
Service is an Application Component, that can perform long-running operations in the background.
Doesn't provide a user interface & can be invoked from another application component. Eg - Download File Service starts from the Button Component.
Types of Services
Foreground Services
The Process is visible to the user. Hence they display a notification E.g. - Downloading a File (Seek-bar shows progress) or playing an audio track.startForegroundService(Intent(this, MyService::class.java))
Background Services
The Process isn't visible to the user. E.g. - Gallery compressing images to store them.
startService(Intent(this, MyService::class.java))
Bound Services
Client-Server Relation between component and service, hence doesn't run in the background. A bound service runs only as long as another application component is bound to it. E.g. - Music Notification to Pause/Play while the app is running in background.
Service Class
Traditional Service Class, which uses the main thread of the application. Android OS gives each application a share of the processor, hence slowing down the application when the service has high requirements or is large.
E.g. - Downloading Slows down when you are simultaneously using that application, as the share of the service is limited.
<!--Defining the service in AndroidManifest.xml file --> <application> .. <service android:name = "ClassicServiceExample"/> </application>
//MainActivit.kt btn.setOnClickListener { val intent = Intent(this@MainActivity, ClassicServiceExample::class.java) startService(intent) ... stopService(intent) //runs onDestroy() method of service. }
//Creating a new Kotlin Class : ClassicServiceExample.kt //extending it with our Service Class & Implementing its members class ClassServiceExample : Service(){ override fun onBind(p0: Intent?) : IBinder? { return null //as we are on not implementing a Bound Service } override fun onStartCommand(intent : Intent?, flags : Int, startId: Int) : Int { //write service here - runs when service started //stopSelf() method when called inside this function, //will destory the service & go to onDestroy() callback return super.onStartCommand(intent, flags, startId) } override fun onDestroy(){ //runs when service destroyed super.onDestroy() } }
Return Value to
onStartCommand()
determines how the Android system should handle a service if it gets killed due to low memory or other constraints.START_STICKY
- system will restart service as soon as resources availableSTART_NOT_STICKY
- system won’t restart serviceSTART_REDELIVER_INTENT
- system restarts task it was handling
//Implementation Example -
private lateinit var player : MediaPlayer //used to play audio and video in Android
override fun onStartCommand(intent : Intent?, flags : Int, startId: Int) : Int {
player = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI)
//initializes a MediaPlayer instance for a specific audio source.
//paramenters - context, URI to ringtone resource
player.isLooping = true
player.start()
return START_STICKY
}
override fun onDestroy(){
//runs when service destroyed
super.onDestroy()
player.stop()
}
Broadcast Receivers in Android
A messaging system that allows communication between the Android OS and Android applications, as well as between different applications. This system is used to send messages regarding system events such as booting, charging, battery indication, and more.
Application can register to receive specific broadcasts. Whenever a system event occurs, a broadcast is sent from the OS or an application, and the system automatically routes broadcasts to apps that have subscribed to receive that particular type of broadcast.
The broadcast message itself is wrapped in an Intent
object whose action string identifies the event that occurred (for example android.intent.action.AIRPLANE_MODE
). The intent may also include additional information bundled into its extra field. For example, the airplane mode intent includes a boolean extra that indicates whether or not Airplane Mode is on.
Some important wide-generated events:
android.intent.action.BATTERY_LOW: Indicates low battery condition on the device.
android.intent.action.BOOT_COMPLETED: This is broadcast once after the system has finished booting
android.intent.action.CALL: To perform a call to someone specified by the data
android.intent.action.DATE_CHANGED: The date has changed
android.intent.action.REBOOT: Have the device reboot
Custom Broadcasts can also be enabled which are send by applications to communicate specific events.
Creating a Broadcast Receiver
Define a BroadcastReceiver class: Extend the
BroadcastReceiver
class & override theonReceive()
method to define the actions to perform when a broadcast is received.Register the BroadcastReceiver:
- Static Registration: Declare the receiver in the
AndroidManifest.xml
- Static Registration: Declare the receiver in the
//AndroidManifest.xml
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
//intent.action is a constant
//representing a specific type of broadcast event or action.
Log.d("BroadcastReceiver", "Device Boot Completed!")
// Perform your action here
}
}
}
- Dynamic Registration: Register the receiver programmatically at runtime using
registerReceiver()
.
class MainActivity : AppCompatActivity() {
private val myReceiver = object : BroadcastReceiver() {
//define an implementation of the BroadcastReceiver class.
override fun onReceive(context: Context, intent: Intent) {
Log.d("BroadcastReceiver", "Custom Broadcast Received!")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Create an IntentFilter to listen for specific broadcasts
// class used to specify the type of broadcasts a BroadcastReceiver
// should listen to.
val filter = IntentFilter("com.example.CUSTOM_BROADCAST")
registerReceiver(myReceiver, filter)
//used to dynamically register a BroadcastReceiver at runtime.
//Links BroadcastReceiver with IntentFilter to start listening for broadcasts.
}
override fun onDestroy() {
super.onDestroy()
// Unregister the receiver to avoid memory leaks
unregisterReceiver(myReceiver)
}
}
//Sending a Broadcast
val intent = Intent("com.example.CUSTOM_BROADCAST")
sendBroadcast(intent)