milosev.com
  • Home
    • List all categories
    • Sitemap
  • Downloads
    • WebSphere
    • Hitachi902
    • Hospital
    • Kryptonite
    • OCR
    • APK
  • About me
    • Gallery
      • Italy2022
      • Côte d'Azur 2024
    • Curriculum vitae
      • Resume
      • Lebenslauf
    • Social networks
      • Facebook
      • Twitter
      • LinkedIn
      • Xing
      • GitHub
      • Google Maps
      • Sports tracker
    • Adventures planning
  1. You are here:  
  2. Home
  3. Android

stopForeground

Details
Written by: Stanko Milosev
Category: Android
Published: 02 May 2022
Last Updated: 02 May 2022
Hits: 1564
  • kotlin
In this article I gave an example on how to start foreground service, but not how to stop it.

In MyService.kt add the code:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
	if (intent?.action.equals("stopForeground")) {
		stopForeground(true)
		stopSelfResult(startId)
	}
	return super.onStartCommand(intent, flags, startId)
}
and in MainActivity.kt I have added new button and onClick:
@RequiresApi(Build.VERSION_CODES.O)
fun stopForegroundServiceAndBroadcastReceiverClick(view: View) {
	val intent = Intent(this, MyService::class.java)
	intent.action = "stopForeground"
	startForegroundService(intent)
}
From here.

startForegroundService and BroadcastReceiver

Details
Written by: Stanko Milosev
Category: Android
Published: 01 May 2022
Last Updated: 01 November 2025
Hits: 2085
  • kotlin
UPDATE: 2025-10-26 LocalBroadcastManager is deprecated

Please refer to this article for BroadcastReceiver in a separate class

In this example I want to start foreground service, and change text in TextView in MainActivity.

First in Android Studio go to File -> New -> Service -> Service and add a service:

In AndroidManifest.xml add FOREGROUND_SERVICE permission:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
* 22023-04-04 UPDATE *

And service:

<service
	android:name=".MyService"
	android:enabled="true"
	android:exported="true"/>

22023-04-04 * ENDOFUPDATE *

Then in service, in my example that is app\src\main\java\com\milosev\startforegroundserviceandbroadcastreceiver\MyService.kt, override onCreate, and the code so that onCreate looks like:
override fun onCreate() {
	super.onCreate()
	sendBroadcastMessage("test")

	val channelId =
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
			createNotificationChannel("my_service", "My Background Service")
		} else {
			// If earlier version channel ID is not used
			// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
			""
		}

	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)
}
Where sendBroadcastMessage looks like:
private fun sendBroadcastMessage(message: String) {
	val intent = Intent("")
	intent.putExtra("message", message)
	LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
and createNotificationChannel:
@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
}
Now MyService.kt looks like:
package com.milosev.startforegroundserviceandbroadcastreceiver

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.location.Location
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager

class MyService : Service() {

    override fun onBind(intent: Intent): IBinder {
        TODO("Return the communication channel to the service.")
    }

    override fun onCreate() {
        super.onCreate()
        sendBroadcastMessage("test")

        val channelId =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                createNotificationChannel("my_service", "My Background Service")
            } else {
                // If earlier version channel ID is not used
                // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
                ""
            }

        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)
    }

    @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
    }

    private fun sendBroadcastMessage(message: String) {
        val intent = Intent("")
        intent.putExtra("message", message)
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    }
}
In MainActivity.kt in onCreate I have added:
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(R.layout.activity_main)

	val broadCastReceiver = object : BroadcastReceiver() {
		override fun onReceive(contxt: Context?, intent: Intent?) {
			val textView = findViewById<TextView>(R.id.textView)
			textView.text = "test"
		}
	}

	LocalBroadcastManager.getInstance(this)
		.registerReceiver(broadCastReceiver, IntentFilter(""))
}
Button click function should look like:
@RequiresApi(Build.VERSION_CODES.O)
fun startForegroundServiceAndBroadcastReceiverClick(view: View) {
	val intent = Intent(this,MyService::class.java)
	startForegroundService(intent)
}
At the end MainActivity.kt looks like:
package com.milosev.startforegroundserviceandbroadcastreceiver

import android.app.Notification
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() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val broadCastReceiver = object : BroadcastReceiver() {
            override fun onReceive(contxt: Context?, intent: Intent?) {
                val textView = findViewById<TextView>(R.id.textView)
                textView.text = "test"
            }
        }

        LocalBroadcastManager.getInstance(this)
            .registerReceiver(broadCastReceiver, IntentFilter(""))
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun startForegroundServiceAndBroadcastReceiverClick(view: View) {
        val intent = Intent(this,MyService::class.java)
        startForegroundService(intent)
    }
}
Please notice in MyService.kt line of code:
val intent = Intent("")
and in MainActivity.kt
LocalBroadcastManager.getInstance(this)
	.registerReceiver(broadCastReceiver, IntentFilter(""))
Otherwise if I want to filter my messages I could instead write MainActivity.kt:
val broadCastReceiver = object : BroadcastReceiver() {
	override fun onReceive(contxt: Context?, intent: Intent?) {
		when (intent?.action) {
			"testFilter" -> {
				val textView = findViewById<TextView>(R.id.textView)
				textView.text = "test"
			}
		}
	}
}

LocalBroadcastManager.getInstance(this)
	.registerReceiver(broadCastReceiver, IntentFilter("testFilter"))
and in MyService.kt:
private fun sendBroadcastMessage(message: String) {
	val intent = Intent("testFilter")
	intent.putExtra("message", message)
	LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
2023-04-04 Update:

\app\src\main\AndroidManifest.xml looks like:

<?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" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.Startforegroundserviceandbroadcastreceiver"
        tools:targetApi="31">

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"/>
        <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>
\app\src\main\res\layout\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/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="@+id/btnStart"
        app:layout_constraintEnd_toEndOf="@+id/btnStart"
        app:layout_constraintStart_toStartOf="@+id/btnStart"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startForegroundServiceAndBroadcastReceiverClick"
        android:text="@string/start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.726" />

</androidx.constraintlayout.widget.ConstraintLayout>

Request location updates

Details
Written by: Stanko Milosev
Category: Android
Published: 01 May 2022
Last Updated: 02 May 2022
Hits: 1464
  • kotlin
Here I gave one example on how to get GPS location, problem with that solution is that location will be calculated once, and not any more, if you need like every few seconds to receive location, this solution will give you same location all the time.

Here is another example to receive updated location.
First I have added fusedLocationClient as private member variable:

private lateinit var fusedLocationClient: FusedLocationProviderClient
Where FusedLocationProviderClient is imported from:
implementation 'com.google.android.gms:play-services-location:19.0.1'
In onCreate I have initialized fusedLocationClient:
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(R.layout.activity_main)
	fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)        
}
I need line like
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
For that I need locationRequest and locationCallback
Both locationRequest and locationCallback I have declared as member variables:
private lateinit var locationCallback: LocationCallback
private lateinit var locationRequest: LocationRequest
locationRequest:
locationRequest = LocationRequest.create().apply {
	interval = 5000
	fastestInterval = 50000
	smallestDisplacement = 170f // 170 m = 0.1 mile
	priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
locationCallback:
locationCallback = object : LocationCallback() {
	override fun onLocationResult(locationResult: LocationResult) {
		locationResult ?: return

		if (locationResult.locations.isNotEmpty()) {
			// get latest location
			val location =
				locationResult.lastLocation
			if (location != null) {
				println(location.latitude.toString())
				println(location.longitude.toString())
			}
		}
	}
}
In app\src\main\AndroidManifest.xml I have added permissions:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And check for permission:
if (ActivityCompat.checkSelfPermission(
		this,
		Manifest.permission.ACCESS_FINE_LOCATION
	) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
		this,
		Manifest.permission.ACCESS_COARSE_LOCATION
	) != PackageManager.PERMISSION_GRANTED
) {
	if (ActivityCompat.shouldShowRequestPermissionRationale(
			this as Activity,
			Manifest.permission.ACCESS_FINE_LOCATION
		)
	) {
		return
	} else {
		ActivityCompat.requestPermissions(
			this,
			arrayOf(
				Manifest.permission.ACCESS_FINE_LOCATION,
			)
			, 99
		)
	}
}
At the end my MainActivity.kt looks like:
package com.milosev.requestlocationupdates

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.view.View
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.*

class MainActivity : AppCompatActivity() {
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationCallback: LocationCallback
    private lateinit var locationRequest: LocationRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    }

    fun requestLocationUpdatesClick(view: View) {

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this as Activity,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            ) {
                return
            } else {
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(
                        Manifest.permission.ACCESS_FINE_LOCATION,
                    )
                    , 99
                )
            }
        }

        locationRequest = LocationRequest.create().apply {
            interval = 5000
            fastestInterval = 50000
            smallestDisplacement = 170f // 170 m = 0.1 mile
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                locationResult ?: return

                if (locationResult.locations.isNotEmpty()) {
                    // get latest location
                    val location =
                        locationResult.lastLocation
                    if (location != null) {
                        println(location.latitude.toString())
                        println(location.longitude.toString())
                    }
                }
            }
        }

        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback,
            Looper.getMainLooper())
    }
}

Write file on internal storage

Details
Written by: Stanko Milosev
Category: Android
Published: 25 April 2022
Last Updated: 25 April 2022
Hits: 1296
  • kotlin
Method to write file:
private fun writeFileOnInternalStorage(mcoContext: Context, sFileName: String?, sBody: String?) {
	val dir = File(mcoContext.getFilesDir(), "mydir")
	if (!dir.exists()) {
		dir.mkdir()
	}
	try {
		val gpxfile = File(dir, sFileName)
		val writer = FileWriter(gpxfile)
		writer.append(sBody)
		writer.flush()
		writer.close()
	} catch (e: Exception) {
		e.printStackTrace()
	}
}
  1. Small example on how to get gps Location
  2. Create Json With Gson
  3. New and improved my list of best applications
  4. New line

Page 7 of 13

  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11