Here I gave simple example of loading google maps in android app. Now I want to load KML file which is on my web site, using simple HttpURLConnection.
First I will add a button for load KML, in order to have clear example, so my layout looks like:
Here is one simplest possible example of google maps.
First start new "Empty Views Activity" like I already explained here
In "\GoogleMapsTestSandBox\app\build.gradle.kts" I have added "com.google.android.gms:play-services-maps:19.2.0", so my dependencies looks like
Since I don't want to make google maps key public, I will add "secrets" file. To do it, first I wil add id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" plugin in gradle "\GoogleMapsTestSandBox\app\build.gradle.kts":
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1"
}
Before I sync my gradle, I need to add two files local.defaults.properties and secrets.properties.
local.defaults.properties:
Here I gave one example of foreground service, but where reciever is in MainActivity.kt.
In this example I want to have receiveer in separate class. So in manifest I will add:
package com.milosev.separateProcessServiceExample
object IntentGlobalActions {
const val TEST_MESSAGE_ACTION = "com.milosev.TEST_MESSAGE_ACTION"
const val START_FOREGROUND_SERVICE = "startService"
}
---
Since LocalBroadcastManager is deprecated, here are examples for creating a separate process Service and sending messages from the process to the UI.
First I created new project with "Empty Views Activity":
Then I have added new service and name it "SeparateProcessServiceExample", please note that later I will derive it from MainScope:
I have disabled exported, since I don't want to share messages between other applications:
In "\SeparateProcessServiceExample\app\src\main\AndroidManifest.xml" I have added permissions for FOREGROUND_SERVICE, and since later I want to display icon in notification when my service starts, I will also need POST_NOTIFICATIONS, also I need FOREGROUND_SERVICE_DATA_SYNC permission because I will want to start with "startForeground" method:
but don't forget to enable viewBinding in your "\SeparateProcessServiceExample\app\build.gradle.kts":
buildFeatures {
viewBinding = true
}
In "\SeparateProcessServiceExample\app\src\main\java\com\milosev\separateProcessServiceExample\SeparateProcessServiceExample.kt" first override onStartCommand and filter pro intent messages defined in IntentGlobalActions, and return START_STICKY:
@RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
IntentGlobalActions.START_FOREGROUND_SERVICE -> {
}
}
return START_STICKY
}
create notification:
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()
Where the method createNotificationChannel looks like:
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String {
val chan = NotificationChannel(
channelId,
channelName, NotificationManager.IMPORTANCE_DEFAULT
)
chan.lightColor = Color.RED
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
Start service:
startForeground(101, notification)
Next, I want to have an endles task, from which I want to send messages like:
In order to use launch my SeparateProcessServiceExample to derive from CoroutineScopebyMainScope(), so now it looks like:
class SeparateProcessServiceExample : Service(), CoroutineScope by MainScope() {
Message sending from service looks like:
val intent = Intent(IntentGlobalActions.TEST_MESSAGE_ACTION)
intent.putExtra("message", "Message number: $messageNumber")
intent.setPackage(packageName)
sendBroadcast(intent)
Now, back to "\SeparateProcessServiceExample\app\src\main\java\com\milosev\separateProcessServiceExample\MainActivity.kt", create reciever like:
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val msg = intent?.getStringExtra("message")
appendLog("Receiver: Got: $msg")
}
}
Register it:
val filter = IntentFilter(IntentGlobalActions.TEST_MESSAGE_ACTION)
registerReceiver(receiver, filter, RECEIVER_NOT_EXPORTED)
Where the method appendLog looks like:
fun appendLog(message: String) {
runOnUiThread {
binding.tvLog.append("\n$message")
val lines = binding.tvLog.text.split("\n")
if (lines.size > maxLines) {
val trimmed = lines.takeLast(maxLines).joinToString("\n")
binding.tvLog.text = trimmed
}
binding.scrollLog.post {
binding.scrollLog.fullScroll(View.FOCUS_DOWN)
}
}
}
To Stop a service from \SeparateProcessServiceExample\app\src\main\java\com\milosev\separateProcessServiceExample\MainActivity.kt I have sent STOP_FOREGROUND_SERVICE:
val intent = Intent(this, SeparateProcessServiceExample::class.java)
intent.action = IntentGlobalActions.STOP_FOREGROUND_SERVICE
startForegroundService(intent)
and in \SeparateProcessServiceExample\app\src\main\java\com\milosev\separateProcessServiceExample\SeparateProcessServiceExample.kt: