Stop location updates in Kotlin Jetpack Compose Android Studio

I’m developing an app with Kotlin Jetpack Compose according to the MVVM pattern.
I would like the position to be acquired only when the user is on the home page, so when he moves to other screens the updates should be stopped.

I am sharing the file relating to the position so that you can see how it is structured:
Posizione.kt

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class Posizione(private val context: Context) {
// FusedLocationProviderClient è utilizzato per ottenere aggiornamenti sulla posizione
var fusedLocationProviderClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
// callback che riceve gli aggiornamenti della posizione
private lateinit var locationCallback: LocationCallback
// configurazione delle richieste di posizione
private var locationRequest: LocationRequest = LocationRequest.create().apply {
interval = 10000 // aggiornamento posizione ogni 10 secondi
fastestInterval = 5000 // intervallo più veloce tra gli aggiornamenti di posizione
priority = LocationRequest.PRIORITY_HIGH_ACCURACY // alta precisione
}
// gestisce gli aggiornamenti di posizione
private var locationUpdateListener: ((Location) -> Unit)? = null
init {
setupLocationCallback() // inizializza il callback della posizione
}
// configura il callback che gestisce gli aggiornamenti della posizione
private fun setupLocationCallback() {
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
Log.d(
"POSIZIONE",
"Posizione attuale: lat ${location.latitude}, lon ${location.longitude}"
)
locationUpdateListener?.invoke(location)
}
}
}
Log.d("POSIZIONE", "Callback di posizione configurato")
}
fun setLocationUpdateListener(update: (Location) -> Unit) {
locationUpdateListener = update
}
// controlla se i permessi di posizione sono stati concessi
fun checkPermissions(): Boolean {
val fineLocationPermission =
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
val coarseLocationPermission =
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
val permissionsGranted =
fineLocationPermission == PackageManager.PERMISSION_GRANTED && coarseLocationPermission == PackageManager.PERMISSION_GRANTED
Log.d("POSIZIONE", "Permessi di localizzazione concessi: $permissionsGranted")
return permissionsGranted
}
// Avvia gli aggiornamenti della posizione se i permessi sono stati concessi
fun startLocationUpdates() {
if (!checkPermissions()) {
Log.d("POSIZIONE", "Permessi di localizzazione non concessi, richiesta in corso...")
return
}
startLocationUpdatesWithPermission()
}
@SuppressLint("MissingPermission")
fun startLocationUpdatesWithPermission() {
Log.d("POSIZIONE", "Inizio aggiornamenti della posizione con permessi concessi")
try {
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
} catch (e: Exception) {
Log.e("POSIZIONE", "Errore durante la richiesta degli aggiornamenti della posizione", e)
}
}
// Interrompe gli aggiornamenti della posizione
fun stopLocationUpdates() {
Log.d("POSIZIONE", "Interruzione aggiornamenti della posizione")
try {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
Log.d("POSIZIONE", "Callback rimosso per gli aggiornamenti della posizione")
} catch (e: Exception) {
Log.e("POSIZIONE", "Errore durante la rimozione degli aggiornamenti della posizione", e)
}
}
// controlla la visualizzazione o meno del pulsante di attivazione dell'oggetto (in InfoOggettoScreen) e restituisce il raggio di attivazione (utilizzato nella HomeScreen ma recuperato da HomeViewModel)
@SuppressLint("MissingPermission")
suspend fun bottoneAttivazione(
oggettoLat: Double,
oggettoLon: Double
): Pair<Boolean, Double> {
var raggio: Double = 100.0
// posizione attuale del dispositivo (è una chiamata asincrona)
val posizioneUtente = withContext(Dispatchers.IO) {
fusedLocationProviderClient.lastLocation.await()
}
if (posizioneUtente != null) {
Log.d(
"Bottone Attivazione",
"Posizione utente: lat ${posizioneUtente.latitude}, lon ${posizioneUtente.longitude}"
)
} else {
Log.d("Bottone Attivazione", "Posizione utente nulla")
}
// distanza tra utente e oggetto
val calcoloDistanza = FloatArray(1)
if (posizioneUtente != null) {
Location.distanceBetween(
posizioneUtente.latitude,
posizioneUtente.longitude,
oggettoLat,
oggettoLon,
calcoloDistanza
)
}
val distanza = calcoloDistanza[0]
Log.d("Bottone Attivazione", "Distanza tra oggetto e utente: $distanza")
val sid =
Credenziali(context).getCredenziali().first.toString() // recupero il sid dal database
val uid =
Credenziali(context).getCredenziali().second?.toInt() // recupero l'uid dal database
val utente = Api.api.getUsersID(uid!!, sid) // recupero le informazioni dell'utente
if (utente.amulet != null) {
Log.d("Bottone Attivazione", "Amuleto equipaggiato")
val amuleto =
Api.api.getObjectsID(utente.amulet, sid) // recupero le informazioni dell'amuleto
Log.d("Bottone Attivazione", "Info amuleto: $amuleto")
if (amuleto.level != null) {
raggio *= (1 + (amuleto.level / 100.0)) // aumento il raggio di attivazione dell'amuleto (secondo la proporzione)
}
} else { // amuleto non equipaggiato (il raggio rimane 100)
Log.d("Bottone Attivazione", "Amuleto non equipaggiato")
}
Log.d("Bottone Attivazione", "Raggio di attivazione: $raggio")
Log.d("Bottone Attivazione", "distanza <= raggio: ${distanza <= raggio}")
return Pair(distanza <= raggio, raggio)
}
}
</code>
<code>class Posizione(private val context: Context) { // FusedLocationProviderClient è utilizzato per ottenere aggiornamenti sulla posizione var fusedLocationProviderClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context) // callback che riceve gli aggiornamenti della posizione private lateinit var locationCallback: LocationCallback // configurazione delle richieste di posizione private var locationRequest: LocationRequest = LocationRequest.create().apply { interval = 10000 // aggiornamento posizione ogni 10 secondi fastestInterval = 5000 // intervallo più veloce tra gli aggiornamenti di posizione priority = LocationRequest.PRIORITY_HIGH_ACCURACY // alta precisione } // gestisce gli aggiornamenti di posizione private var locationUpdateListener: ((Location) -> Unit)? = null init { setupLocationCallback() // inizializza il callback della posizione } // configura il callback che gestisce gli aggiornamenti della posizione private fun setupLocationCallback() { locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { super.onLocationResult(locationResult) for (location in locationResult.locations) { Log.d( "POSIZIONE", "Posizione attuale: lat ${location.latitude}, lon ${location.longitude}" ) locationUpdateListener?.invoke(location) } } } Log.d("POSIZIONE", "Callback di posizione configurato") } fun setLocationUpdateListener(update: (Location) -> Unit) { locationUpdateListener = update } // controlla se i permessi di posizione sono stati concessi fun checkPermissions(): Boolean { val fineLocationPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) val coarseLocationPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) val permissionsGranted = fineLocationPermission == PackageManager.PERMISSION_GRANTED && coarseLocationPermission == PackageManager.PERMISSION_GRANTED Log.d("POSIZIONE", "Permessi di localizzazione concessi: $permissionsGranted") return permissionsGranted } // Avvia gli aggiornamenti della posizione se i permessi sono stati concessi fun startLocationUpdates() { if (!checkPermissions()) { Log.d("POSIZIONE", "Permessi di localizzazione non concessi, richiesta in corso...") return } startLocationUpdatesWithPermission() } @SuppressLint("MissingPermission") fun startLocationUpdatesWithPermission() { Log.d("POSIZIONE", "Inizio aggiornamenti della posizione con permessi concessi") try { fusedLocationProviderClient.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } catch (e: Exception) { Log.e("POSIZIONE", "Errore durante la richiesta degli aggiornamenti della posizione", e) } } // Interrompe gli aggiornamenti della posizione fun stopLocationUpdates() { Log.d("POSIZIONE", "Interruzione aggiornamenti della posizione") try { fusedLocationProviderClient.removeLocationUpdates(locationCallback) Log.d("POSIZIONE", "Callback rimosso per gli aggiornamenti della posizione") } catch (e: Exception) { Log.e("POSIZIONE", "Errore durante la rimozione degli aggiornamenti della posizione", e) } } // controlla la visualizzazione o meno del pulsante di attivazione dell'oggetto (in InfoOggettoScreen) e restituisce il raggio di attivazione (utilizzato nella HomeScreen ma recuperato da HomeViewModel) @SuppressLint("MissingPermission") suspend fun bottoneAttivazione( oggettoLat: Double, oggettoLon: Double ): Pair<Boolean, Double> { var raggio: Double = 100.0 // posizione attuale del dispositivo (è una chiamata asincrona) val posizioneUtente = withContext(Dispatchers.IO) { fusedLocationProviderClient.lastLocation.await() } if (posizioneUtente != null) { Log.d( "Bottone Attivazione", "Posizione utente: lat ${posizioneUtente.latitude}, lon ${posizioneUtente.longitude}" ) } else { Log.d("Bottone Attivazione", "Posizione utente nulla") } // distanza tra utente e oggetto val calcoloDistanza = FloatArray(1) if (posizioneUtente != null) { Location.distanceBetween( posizioneUtente.latitude, posizioneUtente.longitude, oggettoLat, oggettoLon, calcoloDistanza ) } val distanza = calcoloDistanza[0] Log.d("Bottone Attivazione", "Distanza tra oggetto e utente: $distanza") val sid = Credenziali(context).getCredenziali().first.toString() // recupero il sid dal database val uid = Credenziali(context).getCredenziali().second?.toInt() // recupero l'uid dal database val utente = Api.api.getUsersID(uid!!, sid) // recupero le informazioni dell'utente if (utente.amulet != null) { Log.d("Bottone Attivazione", "Amuleto equipaggiato") val amuleto = Api.api.getObjectsID(utente.amulet, sid) // recupero le informazioni dell'amuleto Log.d("Bottone Attivazione", "Info amuleto: $amuleto") if (amuleto.level != null) { raggio *= (1 + (amuleto.level / 100.0)) // aumento il raggio di attivazione dell'amuleto (secondo la proporzione) } } else { // amuleto non equipaggiato (il raggio rimane 100) Log.d("Bottone Attivazione", "Amuleto non equipaggiato") } Log.d("Bottone Attivazione", "Raggio di attivazione: $raggio") Log.d("Bottone Attivazione", "distanza <= raggio: ${distanza <= raggio}") return Pair(distanza <= raggio, raggio) } } </code>
class Posizione(private val context: Context) {

    // FusedLocationProviderClient è utilizzato per ottenere aggiornamenti sulla posizione
    var fusedLocationProviderClient: FusedLocationProviderClient =
        LocationServices.getFusedLocationProviderClient(context)

    // callback che riceve gli aggiornamenti della posizione
    private lateinit var locationCallback: LocationCallback

    // configurazione delle richieste di posizione
    private var locationRequest: LocationRequest = LocationRequest.create().apply {
        interval = 10000 // aggiornamento posizione ogni 10 secondi
        fastestInterval = 5000 // intervallo più veloce tra gli aggiornamenti di posizione
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY // alta precisione
    }

    // gestisce gli aggiornamenti di posizione
    private var locationUpdateListener: ((Location) -> Unit)? = null

    init {
        setupLocationCallback() // inizializza il callback della posizione
    }

    // configura il callback che gestisce gli aggiornamenti della posizione
    private fun setupLocationCallback() {
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                super.onLocationResult(locationResult)
                for (location in locationResult.locations) {
                    Log.d(
                        "POSIZIONE",
                        "Posizione attuale: lat ${location.latitude}, lon ${location.longitude}"
                    )
                    locationUpdateListener?.invoke(location)
                }
            }
        }
        Log.d("POSIZIONE", "Callback di posizione configurato")
    }

    fun setLocationUpdateListener(update: (Location) -> Unit) {
        locationUpdateListener = update
    }

    // controlla se i permessi di posizione sono stati concessi
    fun checkPermissions(): Boolean {
        val fineLocationPermission =
            ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
        val coarseLocationPermission =
            ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
        val permissionsGranted =
            fineLocationPermission == PackageManager.PERMISSION_GRANTED && coarseLocationPermission == PackageManager.PERMISSION_GRANTED

        Log.d("POSIZIONE", "Permessi di localizzazione concessi: $permissionsGranted")
        return permissionsGranted
    }

    // Avvia gli aggiornamenti della posizione se i permessi sono stati concessi
    fun startLocationUpdates() {
        if (!checkPermissions()) {
            Log.d("POSIZIONE", "Permessi di localizzazione non concessi, richiesta in corso...")
            return
        }
        startLocationUpdatesWithPermission()
    }

    @SuppressLint("MissingPermission")
    fun startLocationUpdatesWithPermission() {
        Log.d("POSIZIONE", "Inizio aggiornamenti della posizione con permessi concessi")
        try {
            fusedLocationProviderClient.requestLocationUpdates(
                locationRequest,
                locationCallback,
                Looper.getMainLooper()
            )
        } catch (e: Exception) {
            Log.e("POSIZIONE", "Errore durante la richiesta degli aggiornamenti della posizione", e)
        }
    }

    // Interrompe gli aggiornamenti della posizione
    fun stopLocationUpdates() {
        Log.d("POSIZIONE", "Interruzione aggiornamenti della posizione")
        try {
            fusedLocationProviderClient.removeLocationUpdates(locationCallback)
            Log.d("POSIZIONE", "Callback rimosso per gli aggiornamenti della posizione")
        } catch (e: Exception) {
            Log.e("POSIZIONE", "Errore durante la rimozione degli aggiornamenti della posizione", e)
        }
    }

    // controlla la visualizzazione o meno del pulsante di attivazione dell'oggetto (in InfoOggettoScreen) e restituisce il raggio di attivazione (utilizzato nella HomeScreen ma recuperato da HomeViewModel)
    @SuppressLint("MissingPermission")
    suspend fun bottoneAttivazione(
        oggettoLat: Double,
        oggettoLon: Double
    ): Pair<Boolean, Double> {

        var raggio: Double = 100.0

        // posizione attuale del dispositivo (è una chiamata asincrona)
        val posizioneUtente = withContext(Dispatchers.IO) {
            fusedLocationProviderClient.lastLocation.await()
        }
        if (posizioneUtente != null) {
            Log.d(
                "Bottone Attivazione",
                "Posizione utente: lat ${posizioneUtente.latitude}, lon ${posizioneUtente.longitude}"
            )
        } else {
            Log.d("Bottone Attivazione", "Posizione utente nulla")
        }

        // distanza tra utente e oggetto
        val calcoloDistanza = FloatArray(1)
        if (posizioneUtente != null) {
            Location.distanceBetween(
                posizioneUtente.latitude,
                posizioneUtente.longitude,
                oggettoLat,
                oggettoLon,
                calcoloDistanza
            )
        }
        val distanza = calcoloDistanza[0]
        Log.d("Bottone Attivazione", "Distanza tra oggetto e utente: $distanza")

        val sid =
            Credenziali(context).getCredenziali().first.toString() // recupero il sid dal database
        val uid =
            Credenziali(context).getCredenziali().second?.toInt() // recupero l'uid dal database
        val utente = Api.api.getUsersID(uid!!, sid) // recupero le informazioni dell'utente

        if (utente.amulet != null) {
            Log.d("Bottone Attivazione", "Amuleto equipaggiato")

            val amuleto =
                Api.api.getObjectsID(utente.amulet, sid) // recupero le informazioni dell'amuleto
            Log.d("Bottone Attivazione", "Info amuleto: $amuleto")

            if (amuleto.level != null) {
                raggio *= (1 + (amuleto.level / 100.0)) // aumento il raggio di attivazione dell'amuleto (secondo la proporzione)
            }
        } else { // amuleto non equipaggiato (il raggio rimane 100)
            Log.d("Bottone Attivazione", "Amuleto non equipaggiato")
        }

        Log.d("Bottone Attivazione", "Raggio di attivazione: $raggio")
        Log.d("Bottone Attivazione", "distanza <= raggio: ${distanza <= raggio}")

        return Pair(distanza <= raggio, raggio)

    }

}

I tried to achieve what I described in the HomeScreen with DisposableEffect but I couldn’t.:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>DisposableEffect(navController) {
val listener = NavController.OnDestinationChangedListener { _, destination, _ ->
if (destination.route != "home") {
viewModel.stopLocationUpdates()
} else {
viewModel.startLocationUpdates()
}
}
navController.addOnDestinationChangedListener(listener)
onDispose {
navController.removeOnDestinationChangedListener(listener)
}
}
</code>
<code>DisposableEffect(navController) { val listener = NavController.OnDestinationChangedListener { _, destination, _ -> if (destination.route != "home") { viewModel.stopLocationUpdates() } else { viewModel.startLocationUpdates() } } navController.addOnDestinationChangedListener(listener) onDispose { navController.removeOnDestinationChangedListener(listener) } } </code>
DisposableEffect(navController) {
        val listener = NavController.OnDestinationChangedListener { _, destination, _ ->
            if (destination.route != "home") {
                viewModel.stopLocationUpdates()
            } else {
                viewModel.startLocationUpdates()
            }
        }
        navController.addOnDestinationChangedListener(listener)
        onDispose {
            navController.removeOnDestinationChangedListener(listener)
        }
    }

This is the ViewModel file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class HomeViewModel : ViewModel() {
private val _posizioneUtente = MutableStateFlow<LatLng?>(null)
val posizioneUtente: StateFlow<LatLng?> = _posizioneUtente.asStateFlow()
private lateinit var locationProvider: Posizione
private val _oggettiVirtuali = MutableStateFlow<List<GetObjects>>(emptyList())
val oggettiVirtuali: StateFlow<List<GetObjects>> = _oggettiVirtuali.asStateFlow()
private val _utentiVicini = MutableStateFlow<List<GetUsers>>(emptyList())
val utentiVicini: StateFlow<List<GetUsers>> = _utentiVicini.asStateFlow()
private val _raggioAzione = MutableStateFlow<Int>(100)
val raggioAzione: StateFlow<Int> = _raggioAzione.asStateFlow()
private val _puntiVita = MutableStateFlow<Int>(100)
val puntiVita: StateFlow<Int> = _puntiVita.asStateFlow()
private val _puntiEsperienza = MutableStateFlow<Int>(0)
val puntiEsperienza: StateFlow<Int> = _puntiEsperienza.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private var updateJob: Job? = null
fun initialize(context: Context) {
locationProvider = Posizione(context.applicationContext)
locationProvider.setLocationUpdateListener { location ->
updateJob?.cancel()
_isLoading.value = true
updateJob = viewModelScope.launch {
_posizioneUtente.value = LatLng(location.latitude, location.longitude)
val sid = Credenziali(context).getCredenziali().first.toString()
val lat = location.latitude
val lon = location.longitude
launch {
oggetti(context, sid, lat, lon)
}
launch {
utenti(sid, lat, lon)
}
if (_oggettiVirtuali.value.isNotEmpty()) {
var (_, raggio) = Posizione(context).bottoneAttivazione(
_oggettiVirtuali.value.first().lat,
_oggettiVirtuali.value.first().lon
)
_raggioAzione.value = raggio.toInt()
Log.d("HomeViewModel", "Raggio d'azione aggiornato: ${_raggioAzione.value}")
}
aggiornaVitaEdEsperienza(
sid,
Credenziali(context).getCredenziali().second!!.toInt(),
)
}
_isLoading.value = false
}
startLocationUpdates()
val credenziali = Credenziali(context)
credenziali.verificaECaricaCredenziali(context)
}
private suspend fun oggetti(context: Context, sid: String, lat: Double, lon: Double) {
withContext(Dispatchers.IO) {
try {
val oggettiRicevuti = Api.api.getObjects(sid, lat, lon)
_oggettiVirtuali.value = oggettiRicevuti
val database = Database(context)
database.aggiornaOggettiDB(oggettiRicevuti, Api.api)
Log.d("HomeViewModel", "getObjects - Oggetti virtuali ricevuti: $oggettiRicevuti")
} catch (e: Exception) {
Log.d(
"HomeViewModel",
"getObjects - Errore durante il caricamento degli oggetti: $e"
)
}
}
}
private suspend fun utenti(sid: String, lat: Double, lon: Double) {
withContext(Dispatchers.IO) {
try {
val utentiRicevuti = Api.api.getUsers(sid, lat, lon)
_utentiVicini.value = utentiRicevuti
Log.d("HomeViewModel", "getUsers - Utenti vicini ricevuti: $utentiRicevuti")
} catch (e: Exception) {
Log.d("HomeViewModel", "getUsers - Errore durante il caricamento degli utenti: $e")
}
}
}
private suspend fun aggiornaVitaEdEsperienza(sid: String, uid: Int) {
val utente = Api.api.getUsersID(uid, sid)
_puntiVita.value = utente.life
_puntiEsperienza.value = utente.experience
}
fun startLocationUpdates() {
if (::locationProvider.isInitialized) {
if (locationProvider.checkPermissions()) {
locationProvider.startLocationUpdates()
} else {
Log.d("HomeViewModel", "startLocationUpdates - Permessi non concessi")
}
} else {
Log.d("HomeViewModel", "startLocationUpdates - Location provider non inizializzato")
}
}
fun stopLocationUpdates() {
if (::locationProvider.isInitialized) {
try {
locationProvider.stopLocationUpdates()
Log.d("HomeViewModel", "Interruzione aggiornamenti della posizione")
} catch (e: Exception) {
Log.e(
"HomeViewModel",
"Errore durante l'interruzione degli aggiornamenti della posizione",
e
)
}
} else {
Log.w("HomeViewModel", "LocationProvider non è inizializzato")
}
}
fun clear() {
stopLocationUpdates()
updateJob?.cancel()
}
override fun onCleared() {
super.onCleared()
clear()
}
}
</code>
<code>class HomeViewModel : ViewModel() { private val _posizioneUtente = MutableStateFlow<LatLng?>(null) val posizioneUtente: StateFlow<LatLng?> = _posizioneUtente.asStateFlow() private lateinit var locationProvider: Posizione private val _oggettiVirtuali = MutableStateFlow<List<GetObjects>>(emptyList()) val oggettiVirtuali: StateFlow<List<GetObjects>> = _oggettiVirtuali.asStateFlow() private val _utentiVicini = MutableStateFlow<List<GetUsers>>(emptyList()) val utentiVicini: StateFlow<List<GetUsers>> = _utentiVicini.asStateFlow() private val _raggioAzione = MutableStateFlow<Int>(100) val raggioAzione: StateFlow<Int> = _raggioAzione.asStateFlow() private val _puntiVita = MutableStateFlow<Int>(100) val puntiVita: StateFlow<Int> = _puntiVita.asStateFlow() private val _puntiEsperienza = MutableStateFlow<Int>(0) val puntiEsperienza: StateFlow<Int> = _puntiEsperienza.asStateFlow() private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow() private var updateJob: Job? = null fun initialize(context: Context) { locationProvider = Posizione(context.applicationContext) locationProvider.setLocationUpdateListener { location -> updateJob?.cancel() _isLoading.value = true updateJob = viewModelScope.launch { _posizioneUtente.value = LatLng(location.latitude, location.longitude) val sid = Credenziali(context).getCredenziali().first.toString() val lat = location.latitude val lon = location.longitude launch { oggetti(context, sid, lat, lon) } launch { utenti(sid, lat, lon) } if (_oggettiVirtuali.value.isNotEmpty()) { var (_, raggio) = Posizione(context).bottoneAttivazione( _oggettiVirtuali.value.first().lat, _oggettiVirtuali.value.first().lon ) _raggioAzione.value = raggio.toInt() Log.d("HomeViewModel", "Raggio d'azione aggiornato: ${_raggioAzione.value}") } aggiornaVitaEdEsperienza( sid, Credenziali(context).getCredenziali().second!!.toInt(), ) } _isLoading.value = false } startLocationUpdates() val credenziali = Credenziali(context) credenziali.verificaECaricaCredenziali(context) } private suspend fun oggetti(context: Context, sid: String, lat: Double, lon: Double) { withContext(Dispatchers.IO) { try { val oggettiRicevuti = Api.api.getObjects(sid, lat, lon) _oggettiVirtuali.value = oggettiRicevuti val database = Database(context) database.aggiornaOggettiDB(oggettiRicevuti, Api.api) Log.d("HomeViewModel", "getObjects - Oggetti virtuali ricevuti: $oggettiRicevuti") } catch (e: Exception) { Log.d( "HomeViewModel", "getObjects - Errore durante il caricamento degli oggetti: $e" ) } } } private suspend fun utenti(sid: String, lat: Double, lon: Double) { withContext(Dispatchers.IO) { try { val utentiRicevuti = Api.api.getUsers(sid, lat, lon) _utentiVicini.value = utentiRicevuti Log.d("HomeViewModel", "getUsers - Utenti vicini ricevuti: $utentiRicevuti") } catch (e: Exception) { Log.d("HomeViewModel", "getUsers - Errore durante il caricamento degli utenti: $e") } } } private suspend fun aggiornaVitaEdEsperienza(sid: String, uid: Int) { val utente = Api.api.getUsersID(uid, sid) _puntiVita.value = utente.life _puntiEsperienza.value = utente.experience } fun startLocationUpdates() { if (::locationProvider.isInitialized) { if (locationProvider.checkPermissions()) { locationProvider.startLocationUpdates() } else { Log.d("HomeViewModel", "startLocationUpdates - Permessi non concessi") } } else { Log.d("HomeViewModel", "startLocationUpdates - Location provider non inizializzato") } } fun stopLocationUpdates() { if (::locationProvider.isInitialized) { try { locationProvider.stopLocationUpdates() Log.d("HomeViewModel", "Interruzione aggiornamenti della posizione") } catch (e: Exception) { Log.e( "HomeViewModel", "Errore durante l'interruzione degli aggiornamenti della posizione", e ) } } else { Log.w("HomeViewModel", "LocationProvider non è inizializzato") } } fun clear() { stopLocationUpdates() updateJob?.cancel() } override fun onCleared() { super.onCleared() clear() } } </code>
class HomeViewModel : ViewModel() {

    private val _posizioneUtente = MutableStateFlow<LatLng?>(null)
    val posizioneUtente: StateFlow<LatLng?> = _posizioneUtente.asStateFlow()
    private lateinit var locationProvider: Posizione

    private val _oggettiVirtuali = MutableStateFlow<List<GetObjects>>(emptyList())
    val oggettiVirtuali: StateFlow<List<GetObjects>> = _oggettiVirtuali.asStateFlow()

    private val _utentiVicini = MutableStateFlow<List<GetUsers>>(emptyList())
    val utentiVicini: StateFlow<List<GetUsers>> = _utentiVicini.asStateFlow()

    private val _raggioAzione = MutableStateFlow<Int>(100)
    val raggioAzione: StateFlow<Int> = _raggioAzione.asStateFlow()

    private val _puntiVita = MutableStateFlow<Int>(100)
    val puntiVita: StateFlow<Int> = _puntiVita.asStateFlow()
    private val _puntiEsperienza = MutableStateFlow<Int>(0)
    val puntiEsperienza: StateFlow<Int> = _puntiEsperienza.asStateFlow()

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

    private var updateJob: Job? = null

    fun initialize(context: Context) {
        locationProvider = Posizione(context.applicationContext)

        locationProvider.setLocationUpdateListener { location ->
            updateJob?.cancel()

            _isLoading.value = true
            updateJob = viewModelScope.launch {
                _posizioneUtente.value = LatLng(location.latitude, location.longitude)

                val sid = Credenziali(context).getCredenziali().first.toString()
                val lat = location.latitude
                val lon = location.longitude

                launch {
                    oggetti(context, sid, lat, lon)
                }

                launch {
                    utenti(sid, lat, lon)
                }

                if (_oggettiVirtuali.value.isNotEmpty()) {
                    var (_, raggio) = Posizione(context).bottoneAttivazione(
                        _oggettiVirtuali.value.first().lat,
                        _oggettiVirtuali.value.first().lon
                    )
                    _raggioAzione.value = raggio.toInt()
                    Log.d("HomeViewModel", "Raggio d'azione aggiornato: ${_raggioAzione.value}")
                }

                aggiornaVitaEdEsperienza(
                    sid,
                    Credenziali(context).getCredenziali().second!!.toInt(),
                )
            }
            _isLoading.value = false
        }

        startLocationUpdates()

        val credenziali = Credenziali(context)
        credenziali.verificaECaricaCredenziali(context)
    }

    private suspend fun oggetti(context: Context, sid: String, lat: Double, lon: Double) {
        withContext(Dispatchers.IO) {
            try {
                val oggettiRicevuti = Api.api.getObjects(sid, lat, lon)
                _oggettiVirtuali.value = oggettiRicevuti

                val database = Database(context)
                database.aggiornaOggettiDB(oggettiRicevuti, Api.api)

                Log.d("HomeViewModel", "getObjects - Oggetti virtuali ricevuti: $oggettiRicevuti")
            } catch (e: Exception) {
                Log.d(
                    "HomeViewModel",
                    "getObjects - Errore durante il caricamento degli oggetti: $e"
                )
            }
        }
    }

    private suspend fun utenti(sid: String, lat: Double, lon: Double) {
        withContext(Dispatchers.IO) {
            try {
                val utentiRicevuti = Api.api.getUsers(sid, lat, lon)
                _utentiVicini.value = utentiRicevuti

                Log.d("HomeViewModel", "getUsers - Utenti vicini ricevuti: $utentiRicevuti")
            } catch (e: Exception) {
                Log.d("HomeViewModel", "getUsers - Errore durante il caricamento degli utenti: $e")
            }
        }
    }

    private suspend fun aggiornaVitaEdEsperienza(sid: String, uid: Int) {
        val utente = Api.api.getUsersID(uid, sid)

        _puntiVita.value = utente.life
        _puntiEsperienza.value = utente.experience
    }

    fun startLocationUpdates() {
        if (::locationProvider.isInitialized) {
            if (locationProvider.checkPermissions()) {
                locationProvider.startLocationUpdates()
            } else {
                Log.d("HomeViewModel", "startLocationUpdates - Permessi non concessi")
            }
        } else {
            Log.d("HomeViewModel", "startLocationUpdates - Location provider non inizializzato")
        }
    }

    fun stopLocationUpdates() {
        if (::locationProvider.isInitialized) {
            try {
                locationProvider.stopLocationUpdates()
                Log.d("HomeViewModel", "Interruzione aggiornamenti della posizione")
            } catch (e: Exception) {
                Log.e(
                    "HomeViewModel",
                    "Errore durante l'interruzione degli aggiornamenti della posizione",
                    e
                )
            }
        } else {
            Log.w("HomeViewModel", "LocationProvider non è inizializzato")
        }
    }

    fun clear() {
        stopLocationUpdates()
        updateJob?.cancel()
    }

    override fun onCleared() {
        super.onCleared()
        clear()
    }
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật