How to Get Current Location in Android?
As a developer when you work on locations in Android then you always have some doubts about selecting the best and efficient approach for your requirement. So in this article, we are going to discuss how to get the user’s current location in Android. There are two ways to get the current location of any Android device:
- Android’s Location Manager API
- Fused Location Provider: Google Play Services Location APIs
Question: Which one is efficient and why?
Answer: Fused Location Provider because it optimizes the device’s use of battery power.
Before moving any of the above methods we will have to take location permission.
Taking Location Permission
Step 1: Define uses permissions for location access in the manifest file
<!– To request foreground location access, declare one of these permissions. –>
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<!– Required only when requesting background location access on Android 10 (API level 29) –>
<uses-permission android:name=”android.permission.ACCESS_BACKGROUND_LOCATION” />
Note:
In order to receive location updates from NETWORK_PROVIDER or GPS_PROVIDER, you must request the user’s permission by declaring either the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission, respectively, in your Android manifest file. Without these permissions, your application will fail at runtime when requesting location updates.
If you are using both NETWORK_PROVIDER and GPS_PROVIDER, then you need to request only the ACCESS_FINE_LOCATION permission, because it includes permission for both providers. Permission for ACCESS_COARSE_LOCATION allows access only to NETWORK_PROVIDER.
Step 2: Define uses permission for internet access because we are going to use Internet Provider.
<uses-permission android:name=”android.permission.INTERNET”/>
Step 3: Write a function for checking that location permission is granted or not. If permission is not granted then ask for the permissions in run time.
Kotlin
private fun isLocationPermissionGranted(): Boolean { return if (ActivityCompat.checkSelfPermission( this , android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( this , android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( this , arrayOf( android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION ), requestcode ) false } else { true } } |
Now after handling location permissions, we are going to learn how can we get the location in android.
First Method: By Android’s Location Manager API
We assume that the user has been granted Location Permission. If not then ask first.
Step 1: Creating an instance of LocationManager in the context of LOCATION_SERVICE.
Kotlin
private var currentLocation: Location? = null lateinit var locationManager: LocationManager locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager |
Step 2: Check that if the GPS and Network are available or not and if both are available then we use one with greater accuracy.
Kotlin
val hasGps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) //------------------------------------------------------// val hasNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) |
Step 3: Creating an instance of LocationListener (package: android.location) for both(GPS and Network).
Kotlin
val gpsLocationListener: LocationListener = object : LocationListener { override fun onLocationChanged(location: Location) { locationByGps= location } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } //------------------------------------------------------// val networkLocationListener: LocationListener = object : LocationListener { override fun onLocationChanged(location: Location) { locationByNetwork= location } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } |
Step 4: If any of the GPS or Network providers is enabled then we will request a current location update from the LocationManager with LocationListener.
Kotlin
if (hasGps) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000 , 0F, gpsLocationListener ) } //------------------------------------------------------// if (hasNetwork) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 5000 , 0F, networkLocationListener ) } |
Step 5: Now we check which provider has given us the more accurate location and then we will use that location as per our requirement.
Kotlin
val lastKnownLocationByGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) lastKnownLocationByGps?.let { locationByGps = lastKnownLocationByGps } //------------------------------------------------------// val lastKnownLocationByNetwork = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) lastKnownLocationByNetwork?.let { locationByNetwork = lastKnownLocationByNetwork } //------------------------------------------------------// if (locationByGps != null && locationByNetwork != null ) { if (locationByGps.accuracy > locationByNetwork!!.accuracy) { currentLocation = locationByGps latitude = currentLocation.latitude longitude = currentLocation.longitude // use latitude and longitude as per your need } else { currentLocation = locationByNetwork latitude = currentLocation.latitude longitude = currentLocation.longitude // use latitude and longitude as per your need } } |
Now after learning how can we get the location in android by Location Manager API, we are moving to the second method Fused Location Provider (Google Play Services Location APIs).
Second Method: By Fused Location Provider
We assume that the user has been granted Location Permission. If not then ask first. Fused Location Provider is the Google Play services location APIs. It provides a simple API for getting locations with high, medium, and low accuracy. It also optimizes the device’s use of battery power. So we should prefer this method.
Step 1: Declare variables of FusedLocationProviderClient, LocationRequest, LocationCallback and Location.
Kotlin
// FusedLocationProviderClient - Main class for receiving location updates. private lateinit var fusedLocationProviderClient: FusedLocationProviderClient // LocationRequest - Requirements for the location updates, i.e., // how often you should receive updates, the priority, etc. private lateinit var locationRequest: LocationRequest // LocationCallback - Called when FusedLocationProviderClient // has a new Location private lateinit var locationCallback: LocationCallback // This will store current location info private var currentLocation: Location? = null |
Step 2: Initialize fusedLocationProviderClient.
Kotlin
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient( this ) |
Step 3: Initialize locationRequest.
Kotlin
locationRequest = LocationRequest().apply { // Sets the desired interval for // active location updates. // This interval is inexact. interval = TimeUnit.SECONDS.toMillis( 60 ) // Sets the fastest rate for active location updates. // This interval is exact, and your application will never // receive updates more frequently than this value fastestInterval = TimeUnit.SECONDS.toMillis( 30 ) // Sets the maximum time when batched location // updates are delivered. Updates may be // delivered sooner than this interval maxWaitTime = TimeUnit.MINUTES.toMillis( 2 ) priority = LocationRequest.PRIORITY_HIGH_ACCURACY } |
Step 4: Initialize locationCallback.
Kotlin
locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult?) { super .onLocationResult(locationResult) locationResult?.lastLocation?.let { currentLocation = locationByGps latitude = currentLocation.latitude longitude = currentLocation.longitude // use latitude and longitude as per your need } ?: { Log.d(TAG, "Location information isn't available." ) } } } |
Step 5: Now that you initialized everything, you need to let the FusedLocationProviderClient know that you want to receive updates. So Subscribe to location changes.
Kotlin
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper()) |
Step 6: When the app no longer needs access to location information, it’s important to unsubscribe from location updates.
Kotlin
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback) removeTask.addOnCompleteListener { task -> if (task.isSuccessful) { Log.d(TAG, "Location Callback removed." ) } else { Log.d(TAG, "Failed to remove Location Callback." ) } } |
Now one more important point to give support for Android 10 and Android R. So Let’s talk about it…
Support for Android 10
Step 1: Make these changes in build.gradle file.
- Set compileSdkVersion to 29.
- Set buildToolsVersion to “29.0.3”.
- Set targetSdkVersion to 29.
Your code should look something like this:
android {
compileSdkVersion 29
buildToolsVersion “29.0.3”
defaultConfig {
applicationId “com.example.android.location”
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName “1.0”
}
…
}
Step 2: If you have a foreground service, declare a foregroundServiceType of location in the manifest.
android:foregroundServiceType=”location”
Your code should look something like this:
<application>
…
<!– Foreground services in Android 10+ require type. –>
<service
android:name=”com.example.android.location.ForegroundOnlyLocationService”
android:enabled=”true”
android:exported=”false”
android:foregroundServiceType=”location” />
</application>
Support for Android 11 or Android R
Great news, you don’t need to make changes to any files except for the build.gradle file! Make these changes:
- compileSdkVersion to “android-R”
- targetSdkVersion to “R”
Your code should look something like this:
android {
compileSdkVersion “android-R”
buildToolsVersion “29.0.2”
defaultConfig {
applicationId “com.example.android.location”
minSdkVersion 26
targetSdkVersion “R”
versionCode 1
versionName “1.0”
}
…
}
Please Login to comment...