Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

465
Visualizações
FusedLocationProviderClient con rutinas Kotlin

Estoy tratando de solicitar una nueva ubicación con FusedLocationProviderClient y Kotlin Coroutines. Esta es mi configuración actual:

 class LocationProviderImpl(context: Context) : LocationProvider, CoroutineScope { private val TAG = this::class.java.simpleName private val job = Job() override val coroutineContext: CoroutineContext get() = job + Dispatchers.IO private val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context) private val locationRequest = LocationRequest().apply { numUpdates = 1 priority = LocationRequest.PRIORITY_HIGH_ACCURACY } override suspend fun getLocation(): LatLng = suspendCoroutine { val locationCallback = object : LocationCallback() { override fun onLocationResult(result: LocationResult) { result.lastLocation.run { val latLng = latitude at longitude it.resume(latLng) } fusedLocationProviderClient.removeLocationUpdates(this) } } try { fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper()) } catch (e: SecurityException) { throw NoLocationPermissionException() } } }

Pero cuando intento solicitar una nueva ubicación, obtengo la siguiente excepción:

 java.lang.IllegalStateException: Can't create handler inside thread that has not called Looper.prepare()

Sin embargo, si llamara a Looper.prepare() (y Looper.quit() eventualmente) ¿no significaría que puedo llamar a la función solo una vez?

Cualquier ayuda es apreciada.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

private val locationRequestGPS by lazy { LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setNumUpdates(1) .setExpirationDuration(1000) } private val locationRequestNETWORK by lazy { LocationRequest.create() .setPriority(LocationRequest.PRIORITY_LOW_POWER) .setNumUpdates(1) .setExpirationDuration(1000) } suspend fun getLocation(context: Context, offsetMinutes: Int = 15): Location? = suspendCoroutine { task -> val ctx = context.applicationContext if (!ctx.isPermissionValid(Manifest.permission.ACCESS_COARSE_LOCATION) && !ctx.isPermissionValid(Manifest.permission.ACCESS_FINE_LOCATION)) { task.resume(null) } else { val manager = ctx.getSystemService(Context.LOCATION_SERVICE) as LocationManager if (!LocationManagerCompat.isLocationEnabled(manager)) { task.resume(null) } else { val service = LocationServices.getFusedLocationProviderClient(ctx) service.lastLocation .addOnCompleteListener { locTask -> if (locTask.result == null || System.currentTimeMillis() - locTask.result!!.time > offsetMinutes.minute) { GlobalScope.launch(Dispatchers.Main) { task.resume(locationRequest(manager, service)) } } else { task.resume(locTask.result) } } } } } suspend fun getLocationLast(context: Context): Location? = suspendCoroutine { task -> val ctx = context.applicationContext if (!ctx.isPermissionValid(Manifest.permission.ACCESS_COARSE_LOCATION) && !ctx.isPermissionValid(Manifest.permission.ACCESS_FINE_LOCATION)) { task.resume(null) } else { if (!LocationManagerCompat.isLocationEnabled(ctx.getSystemService(Context.LOCATION_SERVICE) as LocationManager)) { task.resume(null) } else { LocationServices.getFusedLocationProviderClient(ctx) .lastLocation .addOnCompleteListener { locTask -> task.resume(locTask.result) } } } } suspend fun locationRequest(locationManager: LocationManager, service: FusedLocationProviderClient): Location? = suspendCoroutine { task -> val callback = object : LocationCallback() { override fun onLocationResult(p0: LocationResult?) { service.removeLocationUpdates(this) task.resume(p0?.lastLocation) } } when { locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) -> { service.requestLocationUpdates(locationRequestGPS, callback, Looper.getMainLooper()) } locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) -> { service.requestLocationUpdates(locationRequestNETWORK, callback, Looper.getMainLooper()) } else -> { task.resume(null) } } }
over 4 years ago · Santiago Trujillo Relatório

0

Has configurado mal tu coroutineContext . En su lugar, deberías tener

 override val coroutineContext = Dispatchers.MAIN + job

Si alguna vez necesita el despachador de IO , pídale explícitamente:

 withContext(Dispatchers.IO) { ... blocking IO code ... }

Para suspender la rutina, llama a suspendCancellableCoroutine , de lo contrario no obtendrás ningún beneficio de la concurrencia estructurada.

Otro detalle, no escriba ningún código después de él. it.resume en el bloque suspendCancellableCoroutine . Si el despachador elige reanudar la rutina inmediatamente, dentro de la llamada de resume , ese código no se ejecutará hasta que se haya ejecutado todo el código de la rutina (o al menos hasta el siguiente punto de suspensión).

 override fun onLocationResult(result: LocationResult) { fusedLocationProviderClient.removeLocationUpdates(this) it.resume(result.lastLocation.run { latitude at longitude }) }
over 4 years ago · Santiago Trujillo Relatório

0

Al usar suspendCoroutine , invoca el código proporcionado en el despachador que llamó a la función suspendida durante el tiempo de ejecución. Dado que la mayoría de los despachadores no se ejecutan en subprocesos de Looper (prácticamente solo lo hace Dispatchers.MAIN ), la llamada a Looper.myLooper() falla.

La documentación dice que puede reemplazar Looper.myLooper() con null para invocar la devolución de llamada en un hilo no especificado. El despachador de rutina incorporado se asegurará de que se enruta al subproceso correcto para reanudar la ejecución.

EDITAR: es posible que deba llamarlo it.intercepted().resume(latLng) para asegurarse de que el resultado se envíe al hilo correcto. No estoy del todo seguro de si la continuación de suspendCoroutine se intercepta de forma predeterminada.

Además, no necesita llamar a fusedLocationProviderClient.removeLocationUpdates(this) porque ya configuró la cantidad de actualizaciones en LocationRequest en 1 .

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda