快速获取当前位置,一次在android中

时间:2015-04-15 18:25:25

标签: android gps location

我有一个需要设备当前位置(经度和纬度)的Android应用程序。我已经在网上尝试了一些教程,特别是堆栈溢出的一些解决方案,但它们对我来说效果不好。我的要求非常简单:首先我需要它快速并且在片段开始时需要一次位置。其次我需要它尽可能精确,我的意思是如果没有GPS,它应首先使用GPS然后使用网络提供商。

例如,我尝试了this solution,但它在30秒后返回null,但我知道有一些东西都可以,因为谷歌地图和其他应用程序运行良好!

几乎所有答案建议的东西都是使用getLastKnownLocation(),但我想这不是当前的,如果是的话,我不想要它。

任何人都可以建议我使用某种简单快捷的方式来获取位置吗?!

提前致谢

8 个答案:

答案 0 :(得分:66)

在这里,您可以使用此...

使用示例:

public void foo(Context context) {
  // when you need location
  // if inside activity context = this;

  SingleShotLocationProvider.requestSingleUpdate(context, 
   new SingleShotLocationProvider.LocationCallback() {
     @Override public void onNewLocationAvailable(GPSCoordinates location) {
       Log.d("Location", "my location is " + location.toString());
     }
   });
}

您可能想要验证纬度/经度是实际值而不是0或其他值。如果我没记错的话,这不应该抛出NPE,但你可能想要验证它。

public class SingleShotLocationProvider {

  public static interface LocationCallback {
      public void onNewLocationAvailable(GPSCoordinates location);
  }

  // calls back to calling thread, note this is for low grain: if you want higher precision, swap the 
  // contents of the else and if. Also be sure to check gps permission/settings are allowed.
  // call usually takes <10ms
  public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
      final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
      boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
      if (isNetworkEnabled) {
          Criteria criteria = new Criteria();
          criteria.setAccuracy(Criteria.ACCURACY_COARSE);
          locationManager.requestSingleUpdate(criteria, new LocationListener() {
              @Override
              public void onLocationChanged(Location location) {
                  callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
              }

              @Override public void onStatusChanged(String provider, int status, Bundle extras) { }
              @Override public void onProviderEnabled(String provider) { }
              @Override public void onProviderDisabled(String provider) { }
          }, null);
      } else {
          boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
          if (isGPSEnabled) {
              Criteria criteria = new Criteria();
              criteria.setAccuracy(Criteria.ACCURACY_FINE);
              locationManager.requestSingleUpdate(criteria, new LocationListener() {
                  @Override
                  public void onLocationChanged(Location location) {
                      callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
                  }

                  @Override public void onStatusChanged(String provider, int status, Bundle extras) { }
                  @Override public void onProviderEnabled(String provider) { }
                  @Override public void onProviderDisabled(String provider) { }
              }, null);
          }
      }
  }


  // consider returning Location instead of this dummy wrapper class
  public static class GPSCoordinates {
      public float longitude = -1;
      public float latitude = -1;

      public GPSCoordinates(float theLatitude, float theLongitude) {
          longitude = theLongitude;
          latitude = theLatitude;
      }

      public GPSCoordinates(double theLatitude, double theLongitude) {
          longitude = (float) theLongitude;
          latitude = (float) theLatitude;
      }
  }  
}

答案 1 :(得分:3)

<强>的AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
     

Requesting User Permissions

build.gradle (模块:应用)

dependencies {
    ...
    implementation 'com.google.android.gms:play-services-location:15.0.0'
    ...
}
  

如果收到错误,请检查您的顶级build.gradle   包含对google()repo或maven {url的引用   “https://maven.google.com”}

Set Up Google Play Services

<强> LocationService.kt

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.net.Uri
import android.os.Looper
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.*
import org.jetbrains.anko.alert
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.okButton

object LocationService {

    @SuppressLint("StaticFieldLeak")
    private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest
    private val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            doAsync {
                location = locationResult.lastLocation
                onSuccess(location)
            }
        }
    }
    private lateinit var onSuccess: (location : Location) -> Unit
    private lateinit var onError: () -> Unit
    lateinit var location: Location

    fun init(activity: Activity) {
        fusedLocationProviderClient = FusedLocationProviderClient(activity)
        locationRequest = LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(1000).setFastestInterval(1000).setNumUpdates(1)
    }

    private fun checkLocationStatusAndGetLocation(activity: Activity) {
        doAsync {
            when {
                ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> LocationServices.getSettingsClient(activity).checkLocationSettings(LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true).build()).addOnCompleteListener { task ->
                    doAsync {
                        try {
                            task.getResult(ApiException::class.java)
                            fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
                        } catch (exception: ApiException) {
                            when (exception.statusCode) {
                                LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
                                    try {
                                        (exception as ResolvableApiException).startResolutionForResult(activity, 7025)
                                    } catch (ex: Exception) {
                                        promptShowLocation(activity)
                                    }
                                }
                                LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
                                    promptShowLocation(activity)
                                }
                            }
                        }
                    }
                }
                ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) -> activity.runOnUiThread {
                    activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
                        okButton {
                            val ite = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null))
                            ite.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                            activity.startActivity(ite)
                            onError()
                        }
                        negativeButton("Cancelar", { onError() })
                        onCancelled { onError() }
                    }.show()
                }
                else -> ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 7024)
            }
        }
    }

    private fun promptShowLocation(activity: Activity) {
        activity.runOnUiThread {
            activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
                okButton {
                    activity.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
                    onError()
                }
                negativeButton("Cancelar", { onError() })
                onCancelled { onError() }
            }.show()
        }
    }

    fun onRequestPermissionsResult(activity: Activity, requestCode: Int, grantResults: IntArray) {
        if (requestCode == 7024) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                checkLocationStatusAndGetLocation(activity)
            } else {
                onError()
            }
        }
    }

    fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int) {
        if (requestCode == 7025) {
            if (resultCode == Activity.RESULT_OK) {
                checkLocationStatusAndGetLocation(activity)
            } else {
                onError()
            }
        }
    }

    fun getLocation(activity: Activity, onSuccess: () -> Unit, onError: () -> Unit) {
        this.onSuccess = onSuccess
        this.onError = onError
        checkLocationStatusAndGetLocation(activity)
    }

}

您的活动

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    LocationService.init(this)
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    LocationService.onRequestPermissionsResult(this, requestCode, grantResults)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    LocationService.onActivityResult(this, requestCode, resultCode)
}

private fun yourFunction() {
    LocationService.getLocation(this, { location ->
        //TODO: use the location
    }, {
        //TODO: display error message
    })
}

答案 2 :(得分:2)

的AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />

MainActivity.java:

public class MainActivity extends AppCompatActivity implements LocationListener {

    private LocationManager locationManager;
    private Location onlyOneLocation;
    private final int REQUEST_FINE_LOCATION = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
    }

    @Override public void onLocationChanged(Location location) {
        onlyOneLocation = location;
        locationManager.removeUpdates(this);
    }
    @Override public void onStatusChanged(String provider, int status, Bundle extras) { }
    @Override public void onProviderEnabled(String provider) { }
    @Override public void onProviderDisabled(String provider) { }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case REQUEST_FINE_LOCATION:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.d("gps", "Location permission granted");
                try {
                    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
                    locationManager.requestLocationUpdates("gps", 0, 0, this);
                }
                catch (SecurityException ex) {
                    Log.d("gps", "Location permission did not work!");
                }
            }
            break;
    }
}

答案 3 :(得分:2)

对于任何有兴趣以最佳、惯用的方式、使用最新的 API 和 Kotlin 的魔力检索单个位置更新的人,这里是您:

Gradle 依赖:

dependencies {
    ...
    implementation "com.google.android.gms:play-services-location:18.0.0"
    ...
}

清单权限:

<manifest>
    ...
    <!-- required only for LocationRequest.PRIORITY_HIGH_ACCURACY -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
    <!-- required for all other priorities -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    ...
</manifest>

在您的 Extensions 文件中的某处:

// To use PRIORITY_HIGH_ACCURACY, you must have ACCESS_FINE_LOCATION permission.
// Any other priority will require just ACCESS_COARSE_LOCATION,
// but will not guarantee a location update
@SuppressLint("MissingPermission")
suspend fun FusedLocationProviderClient.awaitCurrentLocation(priority: Int): Location? {
    return suspendCancellableCoroutine {
        // to use for request cancellation upon coroutine cancellation
        val cts = CancellationTokenSource()
        getCurrentLocation(priority, cts.token)
            .addOnSuccessListener {location ->
                // remember location is nullable, this happens sometimes
                // when the request expires before an update is acquired
                it.resume(location)
            }.addOnFailureListener {e ->
                it.resumeWithException(e)
            }

        it.invokeOnCancellation {
            cts.cancel()
        }
    }
}

在您的片段中:

// need to register this anywhere before onCreateView, idealy as a field
private val permissionRequester = registerForActivityResult(
    // you can use RequestPermission() contract if you only need 1 permission
    ActivityResultContracts.RequestMultiplePermissions()
) { map ->
    // If you requested 1 permission, change `map` to `isGranted`
    // Keys are permissions Strings, values are isGranted Booleans
    // An easy way to check if "any" permission was granted is map.containsValue(true)
    // You can use your own logic for multiple permissions, 
    // but they have to follow the same checks here:
    val response = map.entries.first()
    val permission = response.key
    val isGranted = response.value
    when {
        isGranted -> onPermissionGranted()
        ActivityCompat.shouldShowRequestPermissionRationale(requireContext(), permission) -> {
            // permission denied but not permanently, tell user why you need it. 
            // Idealy provide a button to request it again and another to dismiss
            AlertDialog.Builder(requireContext())
                .setTitle(R.string.perm_request_rationale_title)
                .setMessage(R.string.perm_request_rationale)
                .setPositiveButton(R.string.request_perm_again) { _, _ -> 
                     requirePermission() 
                }
                .setNegativeButton(R.string.dismiss, null)
                .create()
                .show()
        } 
        else -> {
            // permission permanently denied
            // 1) tell user the app won't work as expected, or
            // 2) take him to your app's info screen to manually change permissions, or
            // 3) silently and gracefully degrade user experience
            // I'll leave the implementation to you
        }
    }
}

onPermissionGranted 函数:

private fun onPermissionGranted() {
    val lm = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
    if(LocationManagerCompat.isLocationEnabled(lm)) {
        // you can do this your own way, eg. from a viewModel
        // but here is where you wanna start the coroutine.
        // Choose your priority based on the permission you required
        val priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        lifecycleScope.launch {
            val location = LocationServices
                .getFusedLocationProviderClient(requireContext())
                .awaitCurrentLocation(priority)
            // do whatever with this location, notice that it's nullable
        }
    } else {
        // prompt user to enable location or launch location settings check
    }
}

现在您要做的就是将其添加到 MyLocation 按钮点击侦听器:

private fun requirePermission() {
    val permissions = arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        // optional: Manifest.permission.ACCESS_COARSE_LOCATION
    )
    permissionRequester.launch(permissions)
}

请注意,这具有检查权限是否已隐式授予的优点,如果是这种情况,则不显示对话框/请求。 因此,始终通过启动请求者来启动流程,并且仅在其回调中进行检查。

答案 4 :(得分:1)

使用LocationManager#requestSingleUpdate可以实现您想要做的事情。此方法将侦听器附加到给定的循环器中(如果您需要或拥有它)并且仅在一次接收时通知该位置。您建议的方法仅用作实际位置之前的不精确位置。

在任何情况下,它都会快于毫秒(除非你有幸在一个位置来到设备时开始收听)。将GPS视为在等待位置时启用的元素,在删除此侦听时禁用。这样做是为了避免耗尽用户的电池。

所以,总结一下:

  • 您开始聆听和获得位置之间的时间取决于设备的GPS(制造商,用户所在地,卫星覆盖范围......)
  • Android SDK中有一种方法可以监听单个更新。
  • 通过提供标准对象,您可以管理哪些标准可供您接收位置。更强的标准意味着有更多的时间来获得准确的回应。

答案 5 :(得分:1)

    // Get LocationManager object
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    // Create a criteria object to retrieve provider
    Criteria criteria = new Criteria();

    // Get the name of the best provider
    String provider = locationManager.getBestProvider(criteria, true);

    // Get Current Location
    Location myLocation = locationManager.getLastKnownLocation(provider);

    //latitude of location
    double myLatitude = myLocation.getLatitude();

    //longitude og location
    double myLongitude = myLocation.getLongitude();

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

答案 6 :(得分:0)

以上所有答案均不适用于我,因此我回答了这个问题 最初添加依赖项

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />

添加类MyLocationListiner.java

之后
package com.example.firebase_auth;

/**
 * Created by Chromicle(Ajay Prabhakar).
 */

import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import static android.content.Context.LOCATION_SERVICE;

public class MyLocationListener implements LocationListener {

    public static double latitude;
    Context ctx;
    Location location;
    LocationManager locationManager;
    boolean isGPSEnabled = false;
    boolean isNetworkEnabled = false;
    public static double longitude;
    MyLocationListener(Context ctx) {
        this.ctx = ctx;
        try {
            locationManager = (LocationManager) ctx.getSystemService(LOCATION_SERVICE);
            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            Toast.makeText(ctx, "GPS Enable " + isGPSEnabled, Toast.LENGTH_LONG).show();
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            Toast.makeText(ctx, "Network Enable " + isNetworkEnabled, Toast.LENGTH_LONG).show();

            if ( Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission
                    ( ctx, android.Manifest.permission.ACCESS_FINE_LOCATION )
                    != PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission( ctx,
                            android.Manifest.permission.ACCESS_COARSE_LOCATION) !=
                            PackageManager.PERMISSION_GRANTED) {  }
            if (isGPSEnabled == true) {
                locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER,     0,       0, this);
                location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            }
            if (isNetworkEnabled==true) {
                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,    0,     0, this);
                location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            // Toast.makeText(ctx,"latitude: "+latitude+" longitude: "+longitude,Toast.LENGTH_LONG).show();


        }
        catch(Exception ex)
        {

            Toast.makeText(ctx,"Exception "+ex, Toast.LENGTH_LONG).show();
        }
    }
    @Nullable
    @Override
    public void onLocationChanged(Location loc)
    {
        loc.getLatitude();
        loc.getLongitude();
        latitude=loc.getLatitude();
        longitude=loc.getLongitude();
    }

    @Override
    public void onProviderDisabled(String provider)
    {
        //print "Currently GPS is Disabled";
    }
    @Override
    public void onProviderEnabled(String provider)
    {
        //print "GPS got Enabled";
    }
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras)
    {

    }
}

要使用该类,请添加此方法 位置存储在地址字符串中

public void getLocation(){
        Double latitude = 0.0, longitude;
        String message = "";
        LocationManager mlocManager = null;
        LocationListener mlocListener;
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener(this);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {

            latitude = MyLocationListener.latitude;
            longitude = MyLocationListener.longitude;
            message = message +"https://www.google.com/maps/dir/@"+ latitude +","+  longitude;
            address=message;
            Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
            if (latitude == 0.0) {
                Toast.makeText(getApplicationContext(), "Currently gps has not found your location....", Toast.LENGTH_LONG).show();
            }

        } else {
            Toast.makeText(getApplicationContext(), "GPS is currently off...", Toast.LENGTH_LONG).show();
        }
    }

希望对您有帮助

答案 7 :(得分:-2)

我已经使用您可以轻松获得当前位置的类创建了一些类。我使用FusedLocationProviderClient获取当前位置。

首先将其添加到清单文件中:

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

然后检查位置权限:

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

checkLocationPermissions方法:

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

checkGPSEnabled方法:

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

startCheckingCurrentLocation方法:

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

对于GPS,我创建了一个类,您可以简单地放置和使用它:

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)
                    }
                }
            }
    }
}

}

为检查位置,我又创建了一个类:

Class LocationUtils( 上下文:上下文, 私有值latLng :(位置:位置)->单位){

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方法:

  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)
}

我创建了一个意图服务来从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)
}

}

在您的片段或活动中使用AddressResultReceiver:

 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
        }

    }
}

您将需要在片段或活动中对此进行初始化,您将在其中使用上述接收方来获取地址:

  private var resultReceiver = AddressResultReceiver(Handler())

这些是应按原样使用的一些常量。

//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"

别忘了在清单文件中添加服务并添加互联网许可:

 <service
        android:name=".ui.account.signin.service.FetchAddressIntentService"
        android:exported="false" />