0% found this document useful (0 votes)
3 views

Module 4

The document discusses the deprecation of AsyncTask in Android and introduces Kotlin Coroutines as a modern alternative for handling asynchronous tasks, emphasizing their lifecycle awareness and efficiency. It also covers the use of Broadcast Receivers for handling system or application events, and explains the different types of services in Android, including foreground, background, and bound services, along with their lifecycle management. Examples are provided for implementing coroutines, broadcast receivers, and services in Android applications.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Module 4

The document discusses the deprecation of AsyncTask in Android and introduces Kotlin Coroutines as a modern alternative for handling asynchronous tasks, emphasizing their lifecycle awareness and efficiency. It also covers the use of Broadcast Receivers for handling system or application events, and explains the different types of services in Android, including foreground, background, and bound services, along with their lifecycle management. Examples are provided for implementing coroutines, broadcast receivers, and services in Android applications.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

Module 4

1. AsyncTask

In Android, handling long-running or potentially blocking operations on the main thread (UI
thread) can cause the application to become unresponsive and result in a poor user experience.
To perform these tasks asynchronously, Android provides several mechanisms. However, one
of the older methods, AsyncTask, has been deprecated since Android API level 30 (Android
11).

Why AsyncTask is Deprecated

AsyncTask was used to perform background operations and publish results on the UI thread
without requiring manual thread management. However, it had several limitations and
problems:
• It is not tied to the lifecycle of an Activity or Fragment, which can lead to memory
leaks.
• Difficulties in handling configuration changes like screen rotations.
• Not designed for more complex tasks or those that require parallel execution or task
prioritization.

Creating Asynchronous Task using Coroutines

• Coroutines in Kotlin provide a simple and efficient way to perform asynchronous


programming.
• They help manage background tasks, such as network requests or database operations,
without blocking the main thread, ensuring smooth and responsive user interfaces in
Android applications.

Coroutine Scope: A lifecycle-bound scope for starting coroutines. Common scopes in Android
include
• viewModelScope
o viewModelScope is an extension property in Android's architecture component
library that provides a coroutine scope tied to the lifecycle of a ViewModel.
o This scope is used to launch coroutines within a ViewModel and ensures that
any coroutines launched are automatically canceled when the ViewModel is
cleared, preventing memory leaks and unnecessary background work.

• lifecycleScope
o lifecycleScope is an extension property provided by Android's Jetpack library
that allows you to launch coroutines tied to the lifecycle of an Activity or
Fragment.
o It helps manage coroutines in a lifecycle-aware way, ensuring that they are
automatically canceled when the lifecycle reaches a certain state
• custom scopes
o User defined scope to launch coroutine.

Dispatcher: Determines the thread on which the coroutine will run:


• Dispatchers.Main: Runs on the main (UI) thread.
• Dispatchers.IO: Runs on a background thread, optimized for I/O operations like
network or database calls.
• Dispatchers.Default: Runs on a background thread, optimized for CPU-intensive
tasks.
• Dispatchers.Unconfined: Not confined to any specific thread; starts in the current
thread but can be moved to other threads.

Suspend Function: A function that can be paused and resumed at a later time. Suspend
functions are at the heart of coroutines and allow them to perform asynchronous operations.

Example: To suspend a coroutine for 2 seconds


Thread.sleep(2000L)
launch vs. async:
• launch:
o Used to start a coroutine that does not return a result.
• async:
o Used to start a coroutine that returns a Deferred result, which can be awaited.

How to Use Coroutines in Android

To use coroutines, you need to add the following dependencies to your build.gradle file:

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-
core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-
android:1.6.4")

Launching Coroutines

import androidx.lifecycle.lifecycleScope

lifecycleScope.launch {
try {
withContext(Dispatchers.IO) {
Thread.sleep(5000L)
//background Tasks
}
// Update the UI with the downloaded data
} catch (e: Exception) {
e.printStackTrace()
}
}
Example Program: This program demonstrates downloading an Image from internet
resource and display using asynchronus background task (coroutine).

Step1: Install Dependencies(coroutine libraries) in build.gradle.kts(Module:app)

// Kotlin Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-
core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-
android:1.6.4")

// OkHttp for network requests


implementation("com.squareup.okhttp3:okhttp:4.9.3")

Step2: Add Permission to AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Step3: UI Design

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:id="@+id/main"
android:layout_marginTop="30dp"
>

<Button
android:id="@+id/downloadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Download Image1" />

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />

<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:scaleType="centerCrop" />

<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/dollar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Dollar Value"/>
<Button
android:id="@+id/convertbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="convert to rupee"/>
<TextView
android:id="@+id/inrview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""/>

</LinearLayout>

Step4: Implementation of Kotlin Activity code to download an Image

class MainActivity : AppCompatActivity() {

private lateinit var imageView: ImageView


private lateinit var progressBar: ProgressBar
private val httpClient = OkHttpClient()

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)

ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) {
v, insets ->
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top,
systemBars.right, systemBars.bottom)
insets
}
val downloadButton: Button =
findViewById(R.id.downloadButton)
imageView = findViewById(R.id.imageView)
progressBar = findViewById(R.id.progressBar)

val dollar:EditText = findViewById(R.id.dollar)


val convertbtn: Button = findViewById(R.id.convertbtn)
val inrview:TextView = findViewById(R.id.inrview)

// Set onClick listener to download image


downloadButton.setOnClickListener {

downloadImage("https://images.pexels.com/photos/3075993/pexels-
photo-3075993.jpeg")
}

convertbtn.setOnClickListener {
if(dollar.text.isNotEmpty()){
var inr = dollar.text.toString().toInt() * 83.2
inrview.text = "INR: $inr"
}
else
Toast.makeText(this,"Enter dollar
value",Toast.LENGTH_SHORT).show()
}
}

// Function to download image using Coroutines


private fun downloadImage(imageUrl: String) {
lifecycleScope.launch {
try {
// Show the ProgressBar before starting the task
progressBar.visibility = android.view.View.VISIBLE

// Download the image on a background thread


val bitmap = withContext(Dispatchers.IO) {
Thread.sleep(5000L)
downloadImageFromUrl(imageUrl)
}

// Update the UI with the downloaded image


imageView.setImageBitmap(bitmap)
} catch (e: Exception) {
e.printStackTrace()
// Handle exceptions (e.g., show an error message)
}
finally {
// Hide the ProgressBar after the task is complete
progressBar.visibility = android.view.View.GONE
}
}
}

// Function to download image from the URL


private fun downloadImageFromUrl(url: String): Bitmap? {
val request = Request.Builder().url(url).build()
httpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw Exception("Failed to
download image")
val inputStream: InputStream? =
response.body?.byteStream()
return BitmapFactory.decodeStream(inputStream)
}
}
}

Your downloadImageFromUrl function is a synchronous function that downloads an image


from a URL and returns it as a Bitmap.

This method blocks the calling thread until the image is fully downloaded and decoded, which
is generally not ideal for UI operations or long-running tasks in Android due to potential
performance issues and blocking of the main thread.

Use of client.newCall(request).execute(): This performs a blocking network request, which


should be done on a background thread.
2. Broadcast Receiver

• Android apps can send or receive broadcast messages from the Android system and
other Android apps, similar to the publish-subscribe design pattern.
• These broadcasts are sent when an event of interest occurs.
o for example, to notify other apps of something that they might be interested in
(for example, some new data has been downloaded).
• Apps can register to receive specific broadcasts. When a broadcast is sent, the system
automatically routes broadcasts to apps that have subscribed to receive that particular
type of broadcast.

Receiving broadcasts

l Apps can receive broadcasts in two ways:


l Manifest-declared receivers
l Context-registered receivers.

Broadcast receiver

l A broadcast receiver (receiver) is an Android component which allows you to register


for system or application events.
l All registered receivers for an event are notified by the Android runtime once this event
happens.

Examples of Android System Generated Broadcast Intent

• android.intent.action.BOOT_COMPLETED
Sent when the device has finished booting.
• android.intent.action.BATTERY_LOW
Broadcast when the battery level is low.
• android.intent.action.ACTION_POWER_CONNECTED
Sent when the device is plugged into power and is charging.
• android.intent.action.ACTION_AIRPLANE_MODE_CHANGED
Broadcast when airplane mode is enabled or disabled.
• android.intent.action.DEVICE_STORAGE_LOW
Sent when the device's available storage is low.
• android.net.wifi.WIFI_STATE_CHANGED
Broadcast when the Wi-Fi state changes (enabled, disabled, enabling, disabling, etc.).
• android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED
Sent when the connection state of the local Bluetooth adapter has changed (e.g.,
connected to or disconnected from a device).

Registering the Broadcast Receiver

1. Manifest-declared receivers (Static)

Manifest-declared receivers are broadcast receivers that are registered in the Android
application's manifest file (AndroidManifest.xml). These receivers allow the application to
listen for specific system or app-level broadcasts, such as changes in network connectivity,
battery levels, or system boot completions, even when the app is not running.

Declared in Manifest: These receivers are registered in the manifest file with
an <receiver> tag and associated intent filters.

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
<!-- other statements -->
<receiver android:name="MyBroadCastReceiver"
android:enabled="true" android:exported="false">
<intent-filter>
<action
android:name="android.intent.action.AIRPLANE_MODE_CHANGED"/>
</intent-filter>
</receiver>

</application>

</manifest>

2. Context Registered Broadcast Receiver(Dynamic)

A context-registered receiver is registered dynamically in your code, usually within the


onCreate() or onStart() methods of an Activity or Service, and is unregistered in onDestroy()
or onStop() to avoid memory leaks.
Implement Receiver class

To receive broadcast from android system, we need to create a class by inheriting from
BroadcastReceiver class

class MyBroadCastReceiver : BroadcastReceiver(){


override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == Intent.ACTION_AIRPLANE_MODE_CHANGED){
Toast.makeText(context,"Airplane
Changed",Toast.LENGTH_LONG).show()
}
}
}

Register the receiver dynamically using the following code,

val intentFilter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)


var myReceiver = MyBroadCastReceiver()
registerReceiver(myReceiver, intentFilter)

Example Program:

package com.example.broascast

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {


private lateinit var myReceiver:BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) {
v, insets ->
val systemBars =
insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top,
systemBars.right, systemBars.bottom)
insets
}

// Register the receiver dynamically when the activity is


resumed
val intentFilter =
IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
myReceiver = MyBroadCastReceiver()
registerReceiver(myReceiver, intentFilter)

}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(myReceiver)
}
}

class MyBroadCastReceiver : BroadcastReceiver(){


override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == Intent.ACTION_AIRPLANE_MODE_CHANGED){
Toast.makeText(context,"Airplane
Changed",Toast.LENGTH_LONG).show()
}
}
}

3. Working with Services

A Service is an application component that can perform long-running operations in the


background. It does not provide a user interface.

Once started, a service might continue running for some time, even after the user switches to
another application.

Additionally, a component can bind to a service to interact with it and even perform
interprocess communication (IPC).

For example, a service can handle network transactions, play music, perform file I/O, or
interact with a content provider, all from the background.
Types of Services

These are the three different types of services:


• Foreground Service: -
o A foreground service performs some operation that is noticeable to the user. For
example, an audio app would use a foreground service to play an audio track.
• Background Service:
o A background service performs an operation that isn't directly noticed by the
user. For example, if an app used a service to compact its storage, that would
usually be a background service.
• Bound Service:
o A service is bound when an application component binds to it by calling
bindService(). A bound service offers a client-server interface that allows
components to interact with the service, send requests, receive results, and even
do so across processes with interprocess communication (IPC). A bound service
runs only as long as another application component is bound to it.

Create a Service

To create a service, you must create a subclass of Service. In your implementation, you must
override some callback methods that handle key aspects of the service lifecycle and provide a
mechanism that allows the components to bind to the service, if appropriate.

These are the most important callback methods that you should override:
• onCreate() The system invokes this method to perform one-time setup procedures when
the service is initially created (before it calls either onStartCommand() or onBind()). If
the service is already running, this method is not called.
• onStartCommand() The system invokes this method by calling startService() when
another component (such as an activity) requests that the service be started. When this
method executes, the service is started and can run in the background indefinitely. If
you implement this, it is your responsibility to stop the service when its work is
complete by calling stopSelf() or stopService(). If you only want to provide binding,
you don't need to implement this method.
• onBind() - The system invokes this method by calling bindService() when another
component wants to bind with the service (such as to perform RPC). In your
implementation of this method, you must provide an interface that clients use to
communicate with the service by returning an IBinder. You must always implement this
method; however, if you don't want to allow binding, you should return null.
• onDestroy() - The system invokes this method when the service is no longer used and
is being destroyed. Your service should implement this to clean up any resources such
as threads, registered listeners, or receivers. This is the last call that the service receives.

Example: Service for playing music file

class MusicService : Service() {


private lateinit var mediaPlayer: MediaPlayer
override fun onCreate() {
super.onCreate()
mediaPlayer = MediaPlayer.create(this,R.raw.sample_music)
mediaPlayer.isLooping = true
Log.d("create","Media Player Created")
}
override fun onStartCommand(intent: Intent?, flags: Int,
startId: Int): Int {
mediaPlayer.start()
Log.d("Start", "Playing...")
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer.stop()
mediaPlayer.release()
Log.d("Destroy", "Stopped")
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

Start the Service

If a component starts the service by calling startService() (which results in a call to


onStartCommand()), the service continues to run until it stops itself with stopSelf() or another
component stops it by calling stopService().

If a component calls bindService() to create the service and onStartCommand() is not called,
the service runs only as long as the component is bound to it. After the service is unbound from
all of its clients, the system destroys it.

Example:

playbtn.setOnClickListener {
val intent = Intent(this,MusicService::class.java)
startService(intent)
}
stopbtn.setOnClickListener {
val intent = Intent(this,MusicService::class.java)
stopService(intent)
}

Full Program to Play a music file

Step 1: Create an android project in Android Studio

Step 2: Add the following permissions in AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission
android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<application
<activity
….
</activity>
</application>

</manifest>

Step 3: Create Service Class in Kotlin

import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.IBinder
import android.util.Log

class MusicService : Service() {


private lateinit var mediaPlayer: MediaPlayer
override fun onCreate() {
super.onCreate()
mediaPlayer = MediaPlayer.create(this,R.raw.sample_music)
mediaPlayer.isLooping = true
Log.d("create","Media Player Created")
}
override fun onStartCommand(intent: Intent?, flags: Int,
startId: Int): Int {
mediaPlayer.start()
Log.d("Start", "Playing...")
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer.stop()
mediaPlayer.release()
Log.d("Destroy", "Stopped")
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

Step 4: Register the MusicService in AndroidManifest.xml using <service> tag after the
<activity> tag

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission
android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<application >
….
<activity
android:name=".MainActivity"
android:exported="true">

</activity>
<service android:name=".MusicService" android:enabled="true"
android:exported="false"/>
</application>

</manifest>

Step 5: Design UI with two buttons (Play and Stop music)

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:id="@+id/playbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="140dp"
android:text="Play Music"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/stopbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="68dp"
android:text="Stop Music"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playbtn" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 5: Implement the kotlin code to start and stop the MusicService in MainActivity.kt

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)

val playbtn:Button = findViewById(R.id.playbtn)


val stopbtn:Button = findViewById(R.id.stopbtn)
playbtn.setOnClickListener {
val intent = Intent(this,MusicService::class.java)
startService(intent)
}
stopbtn.setOnClickListener {
val intent = Intent(this,MusicService::class.java)
stopService(intent)
}
}
}
4. Creating Notifications

A notification is a short message that Android displays outside your app's UI to provide the
user with reminders, communication from other people, or other timely information from your
app.
Users can tap the notification to open your app or take an action directly from the notification.

Appearances on a device

A notification appears as an icon in the status bar, a more detailed entry in the notification
drawer, and a badge on the app's icon.

Status bar and notification drawer:

When you issue a notification, it first appears as an icon in the status bar.

Users can swipe down on the status bar to open the notification drawer, where they can view
more details and take actions with the notification.
A notification remains visible in the notification drawer until it's dismissed by the app or user.

Heads-up notification

Notifications can briefly appear in a floating window called a heads-up notification. This
behavior is normally for important notifications that the user needs to know about immediately,
and it only appears if the device is unlocked.
The heads-up notification appears when your app issues the notification. It disappears after a
moment, but it remains visible in the notification drawer as usual.

Lock Screen Notifications

Notifications can appear on the lock screen. You can programmatically set whether
notifications posted by your app show on a secure lock screen and, if so, the level of detail
visible.

Users can use the system settings to choose the level of detail visible in lock screen notifications
or to disable all lock screen notifications. Starting with Android 8.0, users can disable or enable
lock screen notifications for each notification channel.
Notification Channels

Starting in Android 8.0 (API level 26), all notifications must be assigned to a channel or they
don't appear. This lets users disable specific notification channels for your app instead of
disabling all your notifications. Users can control the visual and auditory options for each
channel from the Android system settings.

An app can have separate channels for each type of notification the app issues. An app can also
create notification channels in response to choices made by users.

The channel is also where you specify the importance level for your notifications on Android
8.0 and higher, so all notifications posted to the same notification channel have the same
behavior.
Notification Importance Level

Android uses the importance of a notification to determine how much the notification interrupts
the user visually and audibly. The higher the importance of a notification, the more interruptive
the notification is.

On Android 8.0 (API level 26) and higher, the importance of a notification is determined by
the importance of the channel the notification is posted to. Users can change the importance of
a notification channel in the system settings, as shown in figure below.
The possible importance levels and the associated notification behaviors are the following:

• Urgent: makes a sound and appears as a heads-up notification.


• High: makes a sound.
• Medium: makes no sound.
• Low: makes no sound and doesn't appear in the status bar.

Notification runtime permission

Android 13 (API level 33) and higher supports a runtime permission for sending non-exempt
(including Foreground Services (FGS)) notifications from an app: POST_NOTIFICATIONS.

This change helps users focus on the notifications that are most important to them.

Declare the permission

The permission that you need to declare in your app's manifest file appears in the following
code snippet:

<manifest>
<uses-permission
android:name="android.permission.POST_NOTIFICATIONS" />

<application
….
</application>

</manifest>

Request for Runtime Permission

if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.POST_NOTIFICATIONS) !=
PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),1001)
}

Create a notification channel

To create a notification channel, follow these steps:

• Construct a NotificationChannel object with a unique channel ID, user-visible name,


and importance level.
• Optionally, specify the description that the user sees in the system settings with
setDescription().
• Register the notification channel by passing it to createNotificationChannel().
fun createNotificationChannel(context: Context) {

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {


val name = "My NotificationChannel"
val descriptionText = "This is my notification channel"
val importance = NotificationManager.IMPORTANCE_HIGH

val channel = NotificationChannel("my_channel_1", name, importance)


channel.description = descriptionText

// Register the channel with the system


val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
notificationManager.createNotificationChannel(channel)

The NotificationChannel object is created with three parameters:


• Channel ID ("my_channel_1"): A unique ID for the channel.
• Name (name): The human-readable name of the channel.
• Importance (importance): The importance level of the channel.

The NotificationManager is retrieved from the system using context.getSystemService. It's cast
to NotificationManager type.

The createNotificationChannel method is called to register the channel with the system. After
this, notifications can be sent through this channel.

Create Notification

A notification in its most basic and compact form—also known as collapsed form—displays
an icon, a title, and a small amount of text content. This section shows how to create a
notification that the user can tap to launch an activity in your app.
fun showNotification(context: Context) {
// Create an intent that will be triggered when the notification
is tapped
val intent = Intent(context, ResponseActivity::class.java)
intent.putExtra("msg","This is the notification content")
val pendingIntent: PendingIntent =
PendingIntent.getActivity(context, 0,
intent,PendingIntent.FLAG_IMMUTABLE )

// Build the notification


val builder = NotificationCompat.Builder(context,
"my_channel_1")
.setSmallIcon(R.drawable.iconimage)
.setContentTitle("Notification Title")
.setContentText("This is the notification content")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()

//Runtime permission request


if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.POST_NOTIFICATIONS) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), 1001 )
}

// Show the notification


val notificationManager =
NotificationManagerCompat.from(context)
notificationManager.notify(1, builder)
}
An Intent is created to specify that when the notification is tapped, the ResponseActivity should
be opened.
An extra piece of data (msg) is added to the intent, which can be retrieved in the
ResponseActivity

A PendingIntent is created, which wraps the Intent. This allows the notification to perform the
specified action (open ResponseActivity) when it is tapped.

PendingIntent.FLAG_IMMUTABLE is used to indicate that the pending intent cannot be


modified after it's created, which is a security feature introduced in newer Android versions.

A NotificationCompat.Builder is created to construct the notification.

The following properties are set:


• setSmallIcon: Specifies the small icon to display in the notification.
• setContentTitle: Sets the title of the notification.
• setContentText: Sets the main content text of the notification.
• setPriority: Defines the importance level of the notification (in this case, high priority).
• setVisibility: Sets the visibility of the notification on the lock screen (in this case,
public).
• setContentIntent: Links the previously created PendingIntent to the notification, so
tapping the notification opens ResponseActivity.
• setAutoCancel: Ensures that the notification is automatically dismissed when the user
taps it.

Finally, a NotificationManagerCompat instance is obtained to manage the notifications.


The notify method is called with a unique notification ID (1 in this case) and the built
notification (builder). This displays the notification in the notification tray.

Example Program:- Create an android project in Android Studio

Step 1: Add Permission POST_NOTIFICATIONS in AndroidManifest.xml

<manifest>
<uses-permission
android:name="android.permission.POST_NOTIFICATIONS" />

<application
….
</application>

</manifest>

Step 2: Create a Button to Show Notification in MainActivity

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="204dp"
android:text="Send Notification"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: Create another Activity called ResponseActivity and include a TextView to show
the full Notification message when user tap on the notification.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ResponseActivity">

<TextView
android:id="@+id/response"
android:layout_width="335dp"
android:layout_height="55dp"
android:layout_marginTop="68dp"
android:ems="10"
android:textColor="#D81B60"
android:textSize="18dp"
android:textAlignment="center"
android:gravity="center_horizontal"
android:inputType="textMultiLine"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Implement the Kotlin Code to Create NotificationChannel and Notification


message in MainActivity.kt

import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Button
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

class MainActivity : AppCompatActivity() {


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)

// Create notification channel (only needed once)


createNotificationChannel(this)

val btn:Button=findViewById(R.id.button)
btn.setOnClickListener {
// Show notification when needed
showNotification(this)
}

}
fun createNotificationChannel(context: Context) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "MyNotificationChannel"
val descriptionText = "This is my notification channel"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel("my_channel_1", name, importance)
channel.description = descriptionText

// Register the channel with the system


val notificationManager: NotificationManager =

context.getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
notificationManager.createNotificationChannel(channel)
}
}

fun showNotification(context: Context) {


// Create an intent that will be triggered when the
notification is tapped
val intent = Intent(context, ResponseActivity::class.java)
intent.putExtra("msg","This is the notification content")
val pendingIntent: PendingIntent =
PendingIntent.getActivity(context, 0,
intent,PendingIntent.FLAG_IMMUTABLE )

// Build the notification


val builder = NotificationCompat.Builder(context,
"my_channel_1")
.setSmallIcon(R.drawable.iconimage)
.setContentTitle("Notification Title")
.setContentText("This is the notification content")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()

//Runtime permission request


if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.POST_NOTIFICATIONS) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), 1001 )
}

// Show the notification


val notificationManager =
NotificationManagerCompat.from(context)
notificationManager.notify(1, builder)
}

Step 5: Implement the Kotlin Code to display the full Notification message in another
activity called ResponseActivity when the notification is tapped.

import android.os.Bundle
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity

class ResponseActivity : AppCompatActivity() {


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_response)

val response:TextView = findViewById(R.id.response)


if(intent!=null) {
response.text = intent.getStringExtra("msg")
}
}
}
When the no(ica,on is tapped, the ResponseAc,vity is opened as given below.

You might also like