get the current location fast and once in android

前端 未结 7 1572
刺人心
刺人心 2020-12-07 10:48

I have an android application that need device current location (latitude and longitude). I\'ve tried some tutorial on the net and specially some solutions from stack overfl

相关标签:
7条回答
  • 2020-12-07 11:48

    I have created some classes using those you can easily get the current location. I used FusedLocationProviderClient for getting the current location.

    First Add this into your manifest File:

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

    Then Check for location permission:

     private fun startCheckingLocation() {
        if (checkLocationPermissions() == true) {
            checkGPSEnabled()
        } else {
            askLocationPermission()
        }
    }
    

    checkLocationPermissions method:

     private fun checkLocationPermissions(): Boolean? {
        return PermissionUtils.hasPermissions(
            requireContext(),
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    }
    

    checkGPSEnabled method:

     private fun checkGPSEnabled() {
        GpsUtils(requireContext()) {
            it?.let {
                startCheckingCurrentLocation()
            }
        }.apply {
            turnGPSOn()
        }
    }
    

    startCheckingCurrentLocation method :

     private fun startCheckingCurrentLocation() {
        LocationUtils(requireContext()) { location ->
            Log.d(TAG, ">>>>>>>>>>>>>>" + location.latitude + " " + location.longitude)
            startIntentService(location)
        }.apply {
            startLocationUpdates()
        }
    }
    

    For GPS I have created one class that you can simply put and use it:

    GPSUtils:

    class GpsUtils(
    private val context: Context,
    private val gpsStatus: (isEnable: Boolean?) -> Unit) {
    
    private val mSettingsClient: SettingsClient = LocationServices.getSettingsClient(context)
    private val mLocationSettingsRequest: LocationSettingsRequest
    private val locationManager: LocationManager =
        context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    private val locationRequest: LocationRequest = LocationRequest.create()
    
    init {
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        locationRequest.interval = 10 * 1000.toLong()
        locationRequest.fastestInterval = 2 * 1000.toLong()
        val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
        mLocationSettingsRequest = builder.build()
        builder.setAlwaysShow(true) //this is the key ingredient
    }
    
    // method for turn on GPS
    fun turnGPSOn() {
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            gpsStatus.invoke(true)
        } else {
            mSettingsClient
                .checkLocationSettings(mLocationSettingsRequest)
                .addOnSuccessListener(
                    (context as Activity)
                ) {
                    //  GPS is already enable, callback GPS status through listener
                    gpsStatus.invoke(true)
                }
                .addOnFailureListener(context) { e ->
                    when ((e as ApiException).statusCode) {
                        LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
                            // Show the dialog by calling startResolutionForResult() and check the result in onActivityResult().
                            val rae = e as ResolvableApiException
                            rae.startResolutionForResult(
                                context,
                                AppConstants.GPS_REQUEST
                            )
                        } catch (sie: IntentSender.SendIntentException) {
                            // Ignore the error.
                            Timber.i(
                                ContentValues.TAG,
                                "PendingIntent unable to execute request."
                            )
                        }
                        LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
                            // Location settings are not satisfied. However, we have no way to fix the
                            // settings so we won't show the dialog.
                            val errorMessage =
                                "Location settings are inadequate, and cannot be fixed here. Fix in Settings."
                            Timber.e(ContentValues.TAG, errorMessage)
                        }
                        LocationSettingsStatusCodes.CANCELED -> {
                            val errorMessage =
                                "Location settings are inadequate, and cannot be fixed here. Fix in Settings."
                            Timber.e(ContentValues.TAG, errorMessage)
                        }
                        LocationSettingsStatusCodes.SUCCESS -> {
                            // All location settings are satisfied. The client can initialize location
                            // requests here.
                            val errorMessage =
                                "Location settings are inadequate, and cannot be fixed here. Fix in Settings."
                            Timber.e(ContentValues.TAG, errorMessage)
                        }
                    }
                }
        }
    }
    

    }

    For checking location I have created one more class :

    class LocationUtils( context: Context, private val latLng: (location: Location) -> Unit) {

    private var fusedLocationClient: FusedLocationProviderClient? = null
    
    private val locationRequest = LocationRequest.create()?.apply {
        interval = 20 * 1000.toLong()
        fastestInterval = 2 * 1000.toLong()
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    }
    
    
    init {
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
    }
    
    /**
     * call when location permission is allowed and you want to fetch the last location of the user
     */
    fun getLastLocation() {
        fusedLocationClient?.lastLocation?.addOnSuccessListener { location ->
            location?.let {
                latLng.invoke(location)
                stopLocationUpdates()
            }
        }
    }
    
    /**
     * Requested location callback
     */
    private val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
    
            locationResult ?: return
    
            for (location in locationResult.locations) {
                location?.let {
                    latLng.invoke(it)
                    stopLocationUpdates()
                }
            }
            super.onLocationResult(locationResult)
        }
    }
    
    /**
     * call when location permission is already given to user and you want to receive continues location updates
     */
    fun startLocationUpdates() {
        fusedLocationClient?.requestLocationUpdates(
            locationRequest,
            locationCallback,
            Looper.getMainLooper()
        )
    }
    
    /**
     * call when you want to stop location updates
     */
    fun stopLocationUpdates() {
        fusedLocationClient?.removeLocationUpdates(locationCallback)?.addOnCompleteListener { }
    }
    

    }

    startIntentService method:

      private fun startIntentService(location: Location?) {
        val intent = Intent(requireActivity(), FetchAddressIntentService::class.java).apply {
            putExtra(AppConstants.RECEIVER, resultReceiver)
            putExtra(AppConstants.LOCATION_DATA_EXTRA, location)
        }
        requireActivity().startService(intent)
    }
    

    I have created one intent service to get the address from latlng:

    class FetchAddressIntentService : IntentService(AppConstants.LOCATION_SERVICE) {
    
    companion object {
        const val TAG = "FetchAddressService"
    }
    
    private var receiver: ResultReceiver? = null
    
    override fun onHandleIntent(intent: Intent?) {
        val geoCoder = Geocoder(this, Locale.getDefault())
        intent ?: return
    
        var errorMessage = ""
    
        // Get the location passed to this service through an extra.
        val location = intent.getParcelableExtra(AppConstants.LOCATION_DATA_EXTRA) as Location
        receiver = intent.getParcelableExtra(AppConstants.RECEIVER) as ResultReceiver
    
        var addresses: List<Address> = emptyList()
    
        try {
            addresses = geoCoder.getFromLocation(location.latitude, location.longitude, 1)
        } catch (ioException: IOException) {
            // Catch network or other I/O problems.
            errorMessage = getString(R.string.service_not_available)
            Log.e(TAG, errorMessage, ioException)
        } catch (illegalArgumentException: IllegalArgumentException) {
            // Catch invalid latitude or longitude values.
            errorMessage = getString(R.string.invalid_lat_long_used)
            Log.e(
                TAG,
                "$errorMessage. Latitude = $location.latitude , Longitude =  $location.longitude",
                illegalArgumentException
            )
        }
    
        // Handle case where no address was found.
        if (addresses.isEmpty()) {
            if (errorMessage.isEmpty()) {
                errorMessage = getString(R.string.no_address_found)
                Log.e(TAG, errorMessage)
            }
            deliverResultToReceiver(AppConstants.FAILURE_RESULT, errorMessage)
        } else {
            val address = addresses[0]
            // Fetch the address lines using getAddressLine,
            // join them, and send them to the thread.
            val addressFragments = with(address) {
                (0..maxAddressLineIndex).map { getAddressLine(it) }
            }
            Log.i(TAG, getString(R.string.address_found))
            deliverResultToReceiver(
                AppConstants.SUCCESS_RESULT,
                addressFragments.joinToString(separator = "\n")
            )
        }
    }
    
    private fun deliverResultToReceiver(resultCode: Int, message: String) {
        val bundle = Bundle().apply { putString(AppConstants.RESULT_DATA_KEY, message) }
        receiver?.send(resultCode, bundle)
    }
    

    }

    Than use AddressResultReceiver in your fragment or activity:

     internal inner class AddressResultReceiver(handler: Handler) : ResultReceiver(handler) {
    
        override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
    
            // Display the address string
            // or an error message sent from the intent service.
            val addressOutput = resultData?.getString(AppConstants.RESULT_DATA_KEY).orEmpty()
            //displayAddressOutput()
            // Show a toast message if an address was found.
            if (resultCode == AppConstants.SUCCESS_RESULT) {
                Boast.showText(requireContext(), "Address found = $addressOutput")
                txtContinueWith.text = addressOutput
            }
    
        }
    }
    

    You will need to initialize this in fragment or activity where you will use the above receiver to get the address:

      private var resultReceiver = AddressResultReceiver(Handler())
    

    These are some constants that you should use as it is.

    //Location Constants
    const val LOCATION_SERVICE = "LOCATION_SERVICE"
    const val SUCCESS_RESULT = 0
    const val FAILURE_RESULT = 1
    const val PACKAGE_NAME = "com.google.android.gms.location.sample.locationaddress"
    const val RECEIVER = "$PACKAGE_NAME.RECEIVER"
    const val RESULT_DATA_KEY = "${PACKAGE_NAME}.RESULT_DATA_KEY"
    const val LOCATION_DATA_EXTRA = "${PACKAGE_NAME}.LOCATION_DATA_EXTRA"
    

    And don't forget to add service in manifest file and also add the internet permission:

     <service
            android:name=".ui.account.signin.service.FetchAddressIntentService"
            android:exported="false" />
    
    0 讨论(0)
提交回复
热议问题