Details                     
                    
     
                    Written by: Stanko Milosev      
        
        
                    
                             Category: Android      
        
        
                    
     
    
        Published: 14 May 2022     
 
        
    
            
                    
     
    
        Last Updated: 01 November 2025     
 
        
                    
     
     
    Hits: 1369 
             
                    
    
    
        
    UPDATE: 2025-10-26
LocalBroadcastManager is 
deprecated  
Please refer to 
this  article for BroadcastReceiver in a separate class
This time I needed to add android:process to my manifest, in order to have a separate never-ending process, and to update UI. 
I have started an empty project, then I have added Service: File -> New -> Service - Service, then I have added Broadcast: File -> New -> Other -> Broadcast receiver.
In AndroidManifest.xml I have added FOREGROUND_SERVICE permission and android:process. Now my manifest looks like:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.milosev.sendbroadcastfromanotherprocess">
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SendBroadcastFromAnotherProcess">
        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" />
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":MyService" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
 
In gradle I have added coroutines:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
 
My gradle looks like:
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}
android {
    compileSdk 32
    defaultConfig {
        applicationId "com.milosev.sendbroadcastfromanotherprocess"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}
dependencies {
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
}
 
MyService.kt:
*2023-04-04 UPDATE: * To debug MyService you will have to attach to this process with debugger.
package com.milosev.sendbroadcastfromanotherprocess
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import kotlinx.coroutines.*
class MyService : Service(), CoroutineScope by MainScope() {
    private var job: Job? = null
    override fun onBind(intent: Intent): IBinder {
        TODO("Return the communication channel to the service.")
    }
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            "startForeground" -> {
                val channelId = createNotificationChannel("my_service", "My Background Service")
                val notificationBuilder = NotificationCompat.Builder(this, channelId)
                val notification = notificationBuilder.setOngoing(true)
                    .setContentTitle("test")
                    .setContentText("test")
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setPriority(1)
                    .setCategory(Notification.CATEGORY_SERVICE)
                    .build()
                startForeground(101, notification)
                val context = this
                job = launch {
                    while(true) {
                        val myIntent = Intent(context, MyReceiver::class.java).setAction("MyAction")
                        myIntent.putExtra("message", "test")
                        sendBroadcast(myIntent);
                        delay(1_000)
                    }
                }
            }
        }
        if (intent?.action.equals("stopForeground")) {
            job?.cancel()
            stopForeground(true)
            stopSelfResult(startId)
        }
        return START_STICKY;
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(channelId: String, channelName: String): String {
        val chan = NotificationChannel(
            channelId,
            channelName, NotificationManager.IMPORTANCE_NONE
        )
        chan.lightColor = Color.RED
        chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        service.createNotificationChannel(chan)
        return channelId
    }
}
 
MyReceiver.kt:
package com.milosev.sendbroadcastfromanotherprocess
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.localbroadcastmanager.content.LocalBroadcastManager
class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val myIntent = Intent(context, MainActivity::class.java).setAction("MyAction")
        myIntent.putExtra("message", "test")
        LocalBroadcastManager.getInstance(context).sendBroadcast(myIntent)
    }
}
 
MainActivity.kt:
package com.milosev.sendbroadcastfromanotherprocess
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.localbroadcastmanager.content.LocalBroadcastManager
class MainActivity : AppCompatActivity() {
    val myReceiver: BroadcastReceiver = MyReceiver()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val filter = IntentFilter("MyAction")
        registerReceiver(myReceiver, filter)
        var textView = findViewById(R.id.myText) as TextView
        val broadCastReceiver = object : BroadcastReceiver() {
            override fun onReceive(contxt: Context?, intent: Intent?) {
                when (intent?.action) {
                    "MyAction" -> {
                        textView = findViewById(R.id.myText) as TextView
                        textView.text = intent.getStringExtra("message")
                    }
                }
            }
        }
        LocalBroadcastManager.getInstance(this)
            .registerReceiver(broadCastReceiver, IntentFilter("MyAction"))
    }
    @RequiresApi(Build.VERSION_CODES.O)
    fun onClick(view: View) {
        val intent = Intent(this, MyService::class.java)
        intent.action = "startForeground"
        startForegroundService(intent)
    }
}
 
activity_main.xml:
<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/myText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Button"
        tools:layout_editor_absoluteX="106dp"
        tools:layout_editor_absoluteY="110dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
 
Example download from 
here .