iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🗺️

FusedLocation - Getting Location Data on Android

に公開

Overview

Previously, LocationManager was used, but it seems that using Google Play Service's FusedLocation is now recommended.
Looking at the official documentation, it appears to provide location information in the most suitable way by considering which provider to use (GPS, Wi-Fi, etc.) and battery efficiency.

Request location permissions

Review the basics of requesting app permissions once more.

  • Request permissions in context when the user starts interacting with a feature that requires them.
  • Do not block the user. Ensure that any UI flow for explaining permissions can always be canceled.
  • If the user denies or revokes a required permission, perform graceful degradation so the app remains usable.
  • Do not assume system behavior.

Types of permissions

  • ACCESS_FINE_LOCATION
    • Uses available location providers like GPS, Wi-Fi, and mobile data to determine the location as accurately as possible.
  • ACCESS_COARSE_LOCATION
    • Uses Wi-Fi, mobile routers, or both to determine the location with an accuracy roughly equivalent to a city block.

Implementation

First, check if the permission has been granted.

    private fun getLocationPermission() {
        val permission = ContextCompat.checkSelfPermission(
            this.applicationContext,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
        if (permission == PackageManager.PERMISSION_GRANTED) {
            requestDeviceLocation()
        } else if (permission == PackageManager.PERMISSION_DENIED) {
            /* Returns true if the user previously denied the request.
               Also returns false if they selected "Don't ask again." */
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            ) {
                // Display UI for explaining to the user here
            } else {
                val requestPermissionLauncher =
                    registerForActivityResult(
                        ActivityResultContracts.RequestPermission()
                    ) { isGranted: Boolean ->
                        if (isGranted) {
                            requestDeviceLocation()
                        } else {
                            Napier.w("Permission not granted")
                        }
                    }
                requestPermissionLauncher.launch(
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            }
        }
    }

Get the last known location


    @SuppressLint("MissingPermission")
    private fun requestDeviceLocation() {
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        try {
            val locationResult = fusedLocationClient.lastLocation
            locationResult.addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    val lastKnownLocation = task.result
                    if (lastKnownLocation != null) {
		        // Use lastKnownLocation.latitude and lastKnownLocation.longitude
                    }
                } else {
                    Napier.i("Request location updates")
                    locationCallback = object : LocationCallback() {
                        override fun onLocationResult(locationResult: LocationResult) {
                            locationResult.lastLocation.also {
		                // Use it.latitude and it.longitude
                            }
                        }
                    }
                    startLocationUpdates()
                    requestingLocationUpdates = true
                }
            }
        } catch (e: SecurityException) {
            Napier.e("SecurityException", e)
        }
    }

    @SuppressLint("MissingPermission")
    private fun startLocationUpdates() {
        locationCallback?.also {
            fusedLocationClient.requestLocationUpdates(
                LocationRequest.create().apply {
                    interval = 5000
                    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
                }, it, this.mainLooper
            )
        }
    }

    override fun onResume() {
        super.onResume()
        if (requestingLocationUpdates) {
            startLocationUpdates()
        }
    }

    override fun onPause() {
        super.onPause()
        locationCallback?.also {
            fusedLocationClient.removeLocationUpdates(it)
        }
    }

Reference URLs

Discussion