Skip to content

Instantly share code, notes, and snippets.

@psteiger
Last active April 14, 2023 12:28
Show Gist options
  • Save psteiger/75e683b89b3ea82ff2047cb3c140e666 to your computer and use it in GitHub Desktop.
Save psteiger/75e683b89b3ea82ff2047cb3c140e666 to your computer and use it in GitHub Desktop.
Location-related Kotlin extension functions for Android.
// Location-related Kotlin extension properties for Android.
// They must be implemented in an Activity because Geocoder needs a context.
// Or else, they must be turned from extension properties to extension functions that receive a context as parameter.
// Example of use
// Use case: show the user his locality name on a TextView
val userLocation = Location(someLatitude, someLongitude)
launch(UI) {
aTextView.text = userLocation.localityName.await()
}
// Returns list of addresses of a given LatLng. Uses Kotlin Coroutines. Does networking - don't use getFromLocation on UI thread.
// private because you probably want other higher-level values (e.g. LatLng.localityName)
private val LatLng.getAddresses: Deferred<List<Address>?>
get() = async {
try {
Geocoder(this@MainActivity, Locale.getDefault()).getFromLocation(latitude, longitude, 1)
} catch (_: IOException) {
null
}
}
// Returns a locality name (most commonly, a city name) given a LatLng. Uses Kotlin Coroutines.
val LatLng.localityName: Deferred<String?>
get() = async { getAddresses.await()?.firstOrNull()?.locality }
// Returns an ISO 3166 country code given a LatLng. Uses Kotlin Coroutines.
val LatLng.countryCode: Deferred<String?>
get() = async { getAddresses.await()?.firstOrNull()?.countryCode }
// Returns the country name given a LatLng. Uses Kotlin Coroutines.
val LatLng.countryName: Deferred<String?>
get() = async { getAddresses.await()?.firstOrNull()?.countryName }
// Converts Location object to LatLng object
val Location.latLng
get() = LatLng(latitude, longitude)
// Avoids having to call location.latLng.localityName - instead call location.localityName
val Location.localityName: Deferred<String?>
get() = latLng.localityName
// Avoids having to call location.latLng.countryCode - instead call location.countryCode
val Location.countryCode: Deferred<String?>
get() = latLng.countryCode
// Avoids having to call location.latLng.countryName - instead call location.countryName
val Location.countryName: Deferred<String?>
get() = latLng.countryName
@dmytrodanylyk
Copy link

dmytrodanylyk commented Jul 4, 2018

Why do you create two coroutines, while you can use one?

private val LatLng.getAddresses: List<Address>?
    get() = ...

val LatLng.localityName: Deferred<String?>
    get() = async { getAddresses?.firstOrNull()?.locality }

@psteiger
Copy link
Author

psteiger commented Jul 4, 2018

@dmytrodanylyk your approach works, but if you would use getAddresses directly, you’d get an exception (networking on UI thread)

Async on getAddresses makes it safe. This safety makes up (for me) for the very small overhead of creating an extra unnecessary coroutine.

@lglf77
Copy link

lglf77 commented Apr 14, 2023

github full working?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment