我需要通过GPS程序获得我的当前位置。 我怎样才能做到呢?
当前回答
到2020年下半年,有一种更简单的方法来做到这一点。
不包括请求权限(我将在底部包含更新的开发人员),下面是代码。
记住,你至少需要在你的依赖项中包含这个版本的库(在应用程序的build.gradle中):
implementation 'com.google.android.gms:play-services-location:17.1.0'
... 当然还有你清单上的准许
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Kotlin(首先是设置):
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(applicationContext)
}
private var cancellationTokenSource = CancellationTokenSource()
然后是主代码(FINE_LOCATION):
private fun requestCurrentLocation() {
// Check Fine permission
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Main code
val currentLocationTask: Task<Location> = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
val result = if (task.isSuccessful) {
val result: Location = task.result
"Location (success): ${result.latitude}, ${result.longitude}"
} else {
val exception = task.exception
"Location (failure): $exception"
}
Log.d(TAG, "getCurrentLocation() result: $result")
}
} else {
// Request fine location permission (full code below).
}
如果你更喜欢Java,它看起来像这样:
public class JavaVersion extends AppCompatActivity {
private final String TAG = "MainActivity";
// The Fused Location Provider provides access to location APIs.
private FusedLocationProviderClient fusedLocationClient;
// Allows class to cancel the location request if it exits the activity.
// Typically, you use one cancellation source per lifecycle.
private final CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
...
private void requestCurrentLocation() {
Log.d(TAG, "requestCurrentLocation()");
// Request permission
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Main code
Task<Location> currentLocationTask = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.getToken()
);
currentLocationTask.addOnCompleteListener((new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
String result = "";
if (task.isSuccessful()) {
// Task completed successfully
Location location = task.getResult();
result = "Location (success): " +
location.getLatitude() +
", " +
location.getLongitude();
} else {
// Task failed with an exception
Exception exception = task.getException();
result = "Exception thrown: " + exception;
}
Log.d(TAG, "getCurrentLocation() result: " + result);
}
}));
} else {
// TODO: Request fine location permission
Log.d(TAG, "Request fine location permission.");
}
}
...
}
的参数:
PRIORITY类型是自解释的。(其他选项是PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER和PRIORITY_NO_POWER。) CancellationToken——如果用户导航离开Activity,这个token允许你取消请求。
操作(Kotlin):
override fun onStop() {
super.onStop()
// Cancels location request (if in flight).
cancellationTokenSource.cancel()
}
就是这样。
现在,这使用FusedLocationProviderClient,这是一个谷歌播放服务api。
这意味着这适用于所有带有谷歌Play Store的Android设备(数量很多)。然而,对于在中国没有Play Store的设备来说,这是行不通的,所以要考虑到这一点。
对于这方面的开发人员来说,如果用户还没有批准,则需要请求精细(或粗略)位置权限,因此在上面的代码中,我将请求位置权限。
下面是完整的代码(在Kotlin中)。
我希望这对你有所帮助(让你的生活更轻松一点)!
/**
* Demonstrates how to easily get the current location via the [FusedLocationProviderClient.getCurrentLocation].
* The main code is in this class's requestCurrentLocation() method.
*/
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// The Fused Location Provider provides access to location APIs.
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(applicationContext)
}
// Allows class to cancel the location request if it exits the activity.
// Typically, you use one cancellation source per lifecycle.
private var cancellationTokenSource = CancellationTokenSource()
// If the user denied a previous permission request, but didn't check "Don't ask again", this
// Snackbar provides an explanation for why user should approve, i.e., the additional rationale.
private val fineLocationRationalSnackbar by lazy {
Snackbar.make(
binding.container,
R.string.fine_location_permission_rationale,
Snackbar.LENGTH_LONG
).setAction(R.string.ok) {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
override fun onStop() {
super.onStop()
// Cancels location request (if in flight).
cancellationTokenSource.cancel()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
Log.d(TAG, "onRequestPermissionResult()")
if (requestCode == REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE) {
when {
grantResults.isEmpty() ->
// If user interaction was interrupted, the permission request
// is cancelled and you receive an empty array.
Log.d(TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED ->
Snackbar.make(
binding.container,
R.string.permission_approved_explanation,
Snackbar.LENGTH_LONG
)
.show()
else -> {
Snackbar.make(
binding.container,
R.string.fine_permission_denied_explanation,
Snackbar.LENGTH_LONG
)
.setAction(R.string.settings) {
// Build intent that displays the App settings screen.
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID,
null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
.show()
}
}
}
}
fun locationRequestOnClick(view: View) {
Log.d(TAG, "locationRequestOnClick()")
requestCurrentLocation()
}
/**
* Gets current location.
* Note: The code checks for permission before calling this method, that is, it's never called
* from a method with a missing permission. Also, I include a second check with my extension
* function in case devs just copy/paste this code.
*/
private fun requestCurrentLocation() {
Log.d(TAG, "requestCurrentLocation()")
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Returns a single current location fix on the device. Unlike getLastLocation() that
// returns a cached location, this method could cause active location computation on the
// device. A single fresh location will be returned if the device location can be
// determined within reasonable time (tens of seconds), otherwise null will be returned.
//
// Both arguments are required.
// PRIORITY type is self-explanatory. (Other options are PRIORITY_BALANCED_POWER_ACCURACY,
// PRIORITY_LOW_POWER, and PRIORITY_NO_POWER.)
// The second parameter, [CancellationToken] allows the activity to cancel the request
// before completion.
val currentLocationTask: Task<Location> = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
val result = if (task.isSuccessful) {
val result: Location = task.result
"Location (success): ${result.latitude}, ${result.longitude}"
} else {
val exception = task.exception
"Location (failure): $exception"
}
Log.d(TAG, "getCurrentLocation() result: $result")
logOutputToScreen(result)
}
} else {
val provideRationale = shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
if (provideRationale) {
fineLocationRationalSnackbar.show()
} else {
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE)
}
}
}
private fun logOutputToScreen(outputString: String) {
val finalOutput = binding.outputTextView.text.toString() + "\n" + outputString
binding.outputTextView.text = finalOutput
}
companion object {
private const val TAG = "MainActivity"
private const val REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE = 34
}
}
其他回答
通过-获取gps位置
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener()
{
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
double latitude = location.getLatitude();
double longitude = location.getLongitude();
double speed = location.getSpeed(); //spedd in meter/minute
speed = (speed*3600)/1000; // speed in km/minute Toast.makeText(GraphViews.this, "Current speed:" + location.getSpeed(),Toast.LENGTH_SHORT).show();
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
获取位置的最佳方法如下所示
// put dependancy
implementation 'com.google.android.gms:play-services-location:11.0.4'
// PUT permissions in Menifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
// create a Java file as below
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);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
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;
}
}
}
// FILE FINISHED
// FETCH LOCATION FROM ACTIVITY AS BELOW
public void getLocation(Context context) {
MyApplication.log(LOG_TAG, "getLocation() ");
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
@Override
public void onNewLocationAvailable(SingleShotLocationProvider.GPSCoordinates loc) {
location = loc;
MyApplication.log(LOG_TAG, "getLocation() LAT: " + location.latitude + ", LON: " + location.longitude);
}
});
}
因为我不喜欢其他答案中的一些代码,下面是我的简单解决方案。这个解决方案意味着在活动或服务中可用来跟踪位置。它确保它永远不会返回太陈旧的数据,除非您显式地请求陈旧的数据。它既可以在回调模式下运行,以便在我们收到更新时获得更新,也可以在轮询模式下运行,以便轮询最新的信息。
通用LocationTracker接口。允许我们有多种类型的位置跟踪器,并轻松插入适当的一个:
package com.gabesechan.android.reusable.location;
import android.location.Location;
public interface LocationTracker {
public interface LocationUpdateListener{
public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime);
}
public void start();
public void start(LocationUpdateListener update);
public void stop();
public boolean hasLocation();
public boolean hasPossiblyStaleLocation();
public Location getLocation();
public Location getPossiblyStaleLocation();
}
ProviderLocationTracker——这个类将跟踪GPS或NETWORK的位置。
package com.gabesechan.android.reusable.location;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class ProviderLocationTracker implements LocationListener, LocationTracker {
// The minimum distance to change Updates in meters
private static final long MIN_UPDATE_DISTANCE = 10;
// The minimum time between updates in milliseconds
private static final long MIN_UPDATE_TIME = 1000 * 60;
private LocationManager lm;
public enum ProviderType{
NETWORK,
GPS
};
private String provider;
private Location lastLocation;
private long lastTime;
private boolean isRunning;
private LocationUpdateListener listener;
public ProviderLocationTracker(Context context, ProviderType type) {
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
if(type == ProviderType.NETWORK){
provider = LocationManager.NETWORK_PROVIDER;
}
else{
provider = LocationManager.GPS_PROVIDER;
}
}
public void start(){
if(isRunning){
//Already running, do nothing
return;
}
//The provider is on, so start getting updates. Update current location
isRunning = true;
lm.requestLocationUpdates(provider, MIN_UPDATE_TIME, MIN_UPDATE_DISTANCE, this);
lastLocation = null;
lastTime = 0;
return;
}
public void start(LocationUpdateListener update) {
start();
listener = update;
}
public void stop(){
if(isRunning){
lm.removeUpdates(this);
isRunning = false;
listener = null;
}
}
public boolean hasLocation(){
if(lastLocation == null){
return false;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return false; //stale
}
return true;
}
public boolean hasPossiblyStaleLocation(){
if(lastLocation != null){
return true;
}
return lm.getLastKnownLocation(provider)!= null;
}
public Location getLocation(){
if(lastLocation == null){
return null;
}
if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
return null; //stale
}
return lastLocation;
}
public Location getPossiblyStaleLocation(){
if(lastLocation != null){
return lastLocation;
}
return lm.getLastKnownLocation(provider);
}
public void onLocationChanged(Location newLoc) {
long now = System.currentTimeMillis();
if(listener != null){
listener.onUpdate(lastLocation, lastTime, newLoc, now);
}
lastLocation = newLoc;
lastTime = now;
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
这是FallbackLocationTracker,它将通过GPS和NETWORK进行跟踪,并使用任何更准确的位置。
package com.gabesechan.android.reusable.location;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
public class FallbackLocationTracker implements LocationTracker, LocationTracker.LocationUpdateListener {
private boolean isRunning;
private ProviderLocationTracker gps;
private ProviderLocationTracker net;
private LocationUpdateListener listener;
Location lastLoc;
long lastTime;
public FallbackLocationTracker(Context context) {
gps = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.GPS);
net = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.NETWORK);
}
public void start(){
if(isRunning){
//Already running, do nothing
return;
}
//Start both
gps.start(this);
net.start(this);
isRunning = true;
}
public void start(LocationUpdateListener update) {
start();
listener = update;
}
public void stop(){
if(isRunning){
gps.stop();
net.stop();
isRunning = false;
listener = null;
}
}
public boolean hasLocation(){
//If either has a location, use it
return gps.hasLocation() || net.hasLocation();
}
public boolean hasPossiblyStaleLocation(){
//If either has a location, use it
return gps.hasPossiblyStaleLocation() || net.hasPossiblyStaleLocation();
}
public Location getLocation(){
Location ret = gps.getLocation();
if(ret == null){
ret = net.getLocation();
}
return ret;
}
public Location getPossiblyStaleLocation(){
Location ret = gps.getPossiblyStaleLocation();
if(ret == null){
ret = net.getPossiblyStaleLocation();
}
return ret;
}
public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime) {
boolean update = false;
//We should update only if there is no last location, the provider is the same, or the provider is more accurate, or the old location is stale
if(lastLoc == null){
update = true;
}
else if(lastLoc != null && lastLoc.getProvider().equals(newLoc.getProvider())){
update = true;
}
else if(newLoc.getProvider().equals(LocationManager.GPS_PROVIDER)){
update = true;
}
else if (newTime - lastTime > 5 * 60 * 1000){
update = true;
}
if(update){
if(listener != null){
listener.onUpdate(lastLoc, lastTime, newLoc, newTime);
}
lastLoc = newLoc;
lastTime = newTime;
}
}
}
由于两者都实现了LocationTracker接口,您可以很容易地改变使用哪一个的想法。要在轮询模式下运行类,只需调用start()。要在更新模式下运行它,请调用start(Listener)。
还可以看看我关于代码的博客文章
如果你正在为Android创建新的位置项目,你应该使用新的谷歌Play位置服务。它更准确,使用起来更简单。
几年来,我一直致力于一个开源的GPS跟踪器项目,GpsTracker。我最近更新了它,以处理来自Android、iOS、Windows Phone和Java ME手机的定期更新。它功能齐全,可以满足您的需要,并且拥有MIT许可证。
GpsTracker中的Android项目使用了新的谷歌播放服务,还有两个服务器堆栈(ASP。NET和PHP)来让你追踪这些手机。
你需要使用latest/最新的
GoogleApiClient Api
基本上你需要做的是:
private GoogleApiClient mGoogleApiClient;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
然后
@Override
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
}
}
为最准确可靠的定位。请看我的帖子:
https://stackoverflow.com/a/33599228/2644905
不要使用LocationListener,它是不准确的,有延迟响应。老实说,这更容易实现。 请阅读文档:https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient
推荐文章
- 何时在Android中使用RxJava,何时使用Android架构组件中的LiveData ?
- 如何在Android项目中使用ThreeTenABP
- 指定的子节点已经有一个父节点。你必须先在子对象的父对象上调用removeView() (Android)
- 我的Android设备没有出现在adb设备列表中
- 在没有安装apk的情况下获取Android .apk文件的VersionName或VersionCode
- Fragment onResume() & onPause()不会在backstack上被调用
- 如何设置基线对齐为假提高性能在线性布局?
- 如何获得当前屏幕方向?
- 如何在Android中渲染PDF文件
- 我如何解决错误“minCompileSdk(31)指定在一个依赖的AAR元数据”在本机Java或Kotlin?
- 如何改变TextInputLayout的浮动标签颜色
- Android工作室如何运行gradle同步手动?
- 如何以编程方式在我的EditText上设置焦点(并显示键盘)
- 如果在片段和活动中同时定义,则不会在片段中调用onRequestPermissionsResult
- 方法setDrawerListener已弃用