Android Get Current Location

Jul 22, 2018

Setup Google Play Services

Edit build.gradle (Module)

dependencies {
    // https://developers.google.com/android/guides/releases
    implementation "com.google.android.gms:play-services-location:15.0.1"
}

NOTE: Set Up Google Play Services.

Specify app permission

Edit AndroidManifest.xml.

<manifest ...>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>

NOTE: ACCESS_COARSE_LOCATION only allow accuracy up to a city block. I need ACCESS_FINE_LOCATION, and I suspect it works better when both are specified.

Get last known location

val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)fusedLocationClient.lastLocation        .addOnSuccessListener { location: Location? ->            // Got last known location. In some rare situations this can be null.            if (location != null) {                // do something, save it perhaps?            }        }

Request location update

Get last known location is nice, but I also want to be sure we have the latest and most accurate location.

// activity private var locationCallback: LocationCallback? = null
val locationRequest = LocationRequest().apply {    interval = 10000    fastestInterval = 5000    priority = LocationRequest.PRIORITY_HIGH_ACCURACY}val builder = LocationSettingsRequest.Builder()        .addLocationRequest(locationRequest)val client = LocationServices.getSettingsClient(activity)val task = client.checkLocationSettings(builder.build())var updateCount = 0task.addOnSuccessListener {    locationCallback = object : LocationCallback() {        override fun onLocationResult(locationResult: LocationResult?) {            updateCount++            locationResult ?: return            for (location in locationResult.locations){                if (location != null) {                    // do something                    Log.d(TAG, "gps.accuracy=${location.accuracy}, speed=${location.speed}, time=${location.time}")                    if (isLocationAccurate(location, true)) {                        stopLocationUpdates()                    }                }            }            // if location is still not accurate after 10 updates, stop the update            if (updateCount > 10) {                stopLocationUpdates()            }        }    }    fusedLocationClient.requestLocationUpdates(locationRequest,            locationCallback,            null /* Looper */)
fun isLocationAccurate(location: Location, isStrict: Boolean): Boolean {    val now = LocalDateTime.now(ZoneOffset.UTC)    val locationTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(location.time), ZoneOffset.UTC)    val seconds = Duration.between(locationTime, now).seconds    if (seconds > 60) {        return false    }    if (location.hasAccuracy()) {        val accuracy = if (isStrict) 20 else 50        if (location.accuracy > accuracy) {            return false        }    }    /*    if (location.hasSpeed()) {        // 10 km/p = 2.77 m/s        if (location.speed > 3) {        }    }     */    return true}
private fun stopLocationUpdates() {    if (locationCallback != null) {        fusedLocationClient.removeLocationUpdates(locationCallback)    }}

NOTE: You might want to pause location update on onPause and resume it onResume.

Permission Request

You also need to handle Permission Request

companion object {     private const val PERMISSION_LOCATION_PHOTO = 1}override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults)    if (requestCode == PERMISSION_LOCATION_PHOTO) {        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {            startLocationUpdates()        }        else {            // fragmentContainer            val snackbar = Snackbar.make(container, getString(R.string.permission_denied_location), Snackbar.LENGTH_INDEFINITE)            snackbar.setAction("Settings") {                val intent = Intent()                intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS                val uri = Uri.fromParts("package", packageName, null)                intent.data = uri                startActivity(intent)            }            snackbar.show()        }    }}
if (PermissionHelper.requestLocationPermission(activity, fragment, PERMISSION_LOCATION_PHOTO, getString(R.string.permission_message_location_photo))) {    startLocationUpdates()}
object PermissionHelper {    fun requestLocationPermission(activity: Activity, fragment: Fragment, requestCode: Int, message: String): Boolean {        return requestPermission(activity, fragment, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), requestCode, message)    }    fun checkLocationPermission(activity: Context): Boolean {        return checkPermission(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION))    }    fun checkPermission(activity: Context?, permissions: Array<String>): Boolean {        for (permission in permissions) {            if (ActivityCompat.checkSelfPermission(activity!!, permission) != PackageManager.PERMISSION_GRANTED)                return false        }        return true    }    fun requestPermission(activity: Activity, fragment: Fragment?, permissions: Array<String>, requestCode: Int, message: String): Boolean {        var context: Context? = activity        if (fragment != null) {            context = fragment.context        }        val isAllow = checkPermission(context, permissions)        if (!isAllow) {            if (ActivityCompat.shouldShowRequestPermissionRationale(activity,                            permissions[0])) {                val dialog = AlertDialog.Builder(context)                        .setMessage(message)                        .setPositiveButton(android.R.string.ok) { dialog, which ->                            if (fragment == null) {                                ActivityCompat.requestPermissions(activity,                                        permissions,                                        requestCode)                            } else {                                fragment.requestPermissions(permissions, requestCode)                            }                        }                        .create()                dialog.show()            } else {                if (fragment == null) {                    ActivityCompat.requestPermissions(activity,                            permissions,                            requestCode)                } else {                    fragment.requestPermissions(permissions, requestCode)                }            }            return false        } else {            return true        }    }}

References:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.