使用融合的 Location Provider 获取当前位置
Posted
技术标签:
【中文标题】使用融合的 Location Provider 获取当前位置【英文标题】:Get current location with fused Location Provider 【发布时间】:2018-08-01 04:15:27 【问题描述】:我有这个活动想要获取当前位置,但现在不知道如何以正确的方式完成它。还有什么是 REQUEST_CODE_ASK_PERMISSIONS? 我必须生成一个吗?
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener
private double longitude;
private double latitude;
private TextView latitudeText, longitudeText;
private FusedLocationProviderClient fusedLocationProviderClient;
private GoogleApiClient googleApiClient;
private LocationManager locationManager;
private LocationListener locationListener;
private LocationRequest locationRequest;
private LocationCallback locationCallback;
final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
latitudeText = findViewById(R.id.latitudeText);
longitudeText = findViewById(R.id.longitudeText);
getLocation();
private void getLocation()
locationRequest = new LocationRequest()
.setInterval(2000).setFastestInterval(2000).setPriority(1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
locationCallback = new LocationCallback()
@Override
public void onLocationResult(LocationResult locationResult)
for (Location location : locationResult.getLocations())
latitude = location.getLatitude();
longitude = location.getLongitude();
latitudeText.setText(String.valueOf(latitude));
longitudeText.setText(String.valueOf(longitude));
;
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>()
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse)
);
@Override
protected void onResume()
super.onResume();
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(MainActivity.this,new String[]Manifest
.permission.ACCESS_FINE_LOCATION,REQUEST_CODE_ASK_PERMISSIONS);
else if()
@Override
public void onConnected(@Nullable Bundle bundle)
@Override
public void onConnectionSuspended(int i)
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
.................................................. ..................................................... ..................................................... ..
【问题讨论】:
【参考方案1】:在 build.gradle (Module:app) 中添加依赖
implementation 'com.google.android.gms:play-services-location:16.0.0'
在清单中声明必要的权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
EasyLocationProvider.java
import android.annotation.SuppressLint;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.tasks.OnCanceledListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
public class EasyLocationProvider implements LifecycleObserver
private EasyLocationCallback callback;
private Context context;
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationCallback mLocationCallback;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private LocationSettingsRequest mLocationSettingsRequest;
private long interval;
private long fastestInterval;
private int priority;
private double Latitude = 0.0, Longitude = 0.0;
private EasyLocationProvider(final Builder builder)
context = builder.context;
callback = builder.callback;
interval = builder.interval;
fastestInterval = builder.fastestInterval;
priority = builder.priority;
@SuppressLint("MissingPermission")
public void requestLocationUpdate()
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
private void connectGoogleClient()
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int resultCode = googleAPI.isGooglePlayServicesAvailable(context);
if (resultCode == ConnectionResult.SUCCESS)
mGoogleApiClient.connect();
else
int REQUEST_GOOGLE_PLAY_SERVICE = 988;
googleAPI.getErrorDialog((AppCompatActivity) context, resultCode, REQUEST_GOOGLE_PLAY_SERVICE);
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateLocationProvider()
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void onLocationResume()
buildGoogleApiClient();
@SuppressLint("MissingPermission")
private synchronized void buildGoogleApiClient()
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
mSettingsClient = LocationServices.getSettingsClient(context);
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks()
@Override
public void onConnected(@Nullable Bundle bundle)
callback.onGoogleAPIClient(mGoogleApiClient, "Connected");
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(interval);
mLocationRequest.setFastestInterval(fastestInterval);
mLocationRequest.setPriority(priority);
mLocationRequest.setSmallestDisplacement(0);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
mLocationSettingsRequest = builder.build();
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>()
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse)
showLog("GPS is Enabled Requested Location Update");
requestLocationUpdate();
).addOnFailureListener(new OnFailureListener()
@Override
public void onFailure(@NonNull Exception e)
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode)
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try
int REQUEST_CHECK_SETTINGS = 214;
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult((AppCompatActivity) context, REQUEST_CHECK_SETTINGS);
catch (IntentSender.SendIntentException sie)
showLog("Unable to Execute Request");
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
showLog("Location Settings are Inadequate, and Cannot be fixed here. Fix in Settings");
).addOnCanceledListener(new OnCanceledListener()
@Override
public void onCanceled()
showLog("onCanceled");
);
@Override
public void onConnectionSuspended(int i)
connectGoogleClient();
callback.onGoogleAPIClient(mGoogleApiClient, "Connection Suspended");
)
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener()
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
callback.onGoogleAPIClient(mGoogleApiClient, "" + connectionResult.getErrorCode() + " " + connectionResult.getErrorMessage());
)
.addApi(LocationServices.API)
.build();
connectGoogleClient();
mLocationCallback = new LocationCallback()
@Override
public void onLocationResult(final LocationResult locationResult)
super.onLocationResult(locationResult);
Latitude = locationResult.getLastLocation().getLatitude();
Longitude = locationResult.getLastLocation().getLongitude();
if (Latitude == 0.0 && Longitude == 0.0)
showLog("New Location Requested");
requestLocationUpdate();
else
callback.onLocationUpdated(Latitude, Longitude);
;
@SuppressLint("MissingPermission")
public void removeUpdates()
try
callback.onLocationUpdateRemoved();
catch (Exception e)
e.printStackTrace();
private void showLog(String message)
Log.e("EasyLocationProvider", "" + message);
public interface EasyLocationCallback
void onGoogleAPIClient(GoogleApiClient googleApiClient, String message);
void onLocationUpdated(double latitude, double longitude);
void onLocationUpdateRemoved();
public static class Builder
private Context context;
private EasyLocationCallback callback;
private long interval = 10 * 1000;
private long fastestInterval = 5 * 1000;
private int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
public Builder(Context context)
this.context = context;
public EasyLocationProvider build()
if (callback == null)
Toast.makeText(context, "EasyLocationCallback listener can not be null", Toast.LENGTH_SHORT).show();
return new EasyLocationProvider(this);
public Builder setListener(EasyLocationCallback callback)
this.callback = callback;
return this;
public Builder setInterval(long interval)
this.interval = interval;
return this;
public Builder setFastestInterval(int fastestInterval)
this.fastestInterval = fastestInterval;
return this;
public Builder setPriority(int priority)
this.priority = priority;
return this;
用途:
EasyLocationProvider easyLocationProvider; //Declare Global Variable
easyLocationProvider = new EasyLocationProvider.Builder(BottomNavigationActivity.this)
.setInterval(5000)
.setFastestInterval(2000)
//.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setListener(new EasyLocationProvider.EasyLocationCallback()
@Override
public void onGoogleAPIClient(GoogleApiClient googleApiClient, String message)
Log.e("EasyLocationProvider","onGoogleAPIClient: "+message);
@Override
public void onLocationUpdated(double latitude, double longitude)
Log.e("EasyLocationProvider","onLocationUpdated:: "+ "Latitude: "+latitude+" Longitude: "+longitude);
@Override
public void onLocationUpdateRemoved()
Log.e("EasyLocationProvider","onLocationUpdateRemoved");
).build();
getLifecycle().addObserver(easyLocationProvider);
移除位置更新回调
@Override
protected void onDestroy()
easyLocationProvider.removeUpdates();
getLifecycle().removeObserver(easyLocationProvider);
super.onDestroy();
注意:授予 Marshmallow 及更高版本设备的权限
【讨论】:
【参考方案2】:你应该覆盖onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
switch (requestCode)
case REQUEST_CODE_ASK_PERMISSIONS:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
getLocation();
所以由你来定义REQUEST_CODE_ASK_PERMISSIONS
,它的作用是处理回调,特别是如果你要求的不仅仅是权限。
我认为您的 getLocation()
使用了已弃用的 API。看看here如何获取位置。
【讨论】:
【参考方案3】:Ketan Ramani 的回答帮助了我,所有的功劳都归功于他。我做了一些调整,以便能够设置更新的数量,尤其是在只需要一个的情况下。
public class LocationProvider implements LifecycleObserver
private EasyLocationCallback callback;
private Context context;
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationCallback mLocationCallback;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private LocationSettingsRequest mLocationSettingsRequest;
private long interval;
private long fastestInterval;
private int priority;
private int numberOfUpdates;
private double Latitude = 0.0, Longitude = 0.0;
private LocationProvider(final Builder builder)
context = builder.context;
callback = builder.callback;
interval = builder.interval;
fastestInterval = builder.fastestInterval;
priority = builder.priority;
numberOfUpdates = builder.numberOfUpdates;
@SuppressLint("MissingPermission")
public void requestLocationUpdate()
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
private void connectGoogleClient()
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int resultCode = googleAPI.isGooglePlayServicesAvailable(context);
if (resultCode == ConnectionResult.SUCCESS)
mGoogleApiClient.connect();
else
int REQUEST_GOOGLE_PLAY_SERVICE = 988;
googleAPI.getErrorDialog((AppCompatActivity) context, resultCode, REQUEST_GOOGLE_PLAY_SERVICE);
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateLocationProvider()
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void onLocationResume()
buildGoogleApiClient();
@SuppressLint("MissingPermission")
private synchronized void buildGoogleApiClient()
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
mSettingsClient = LocationServices.getSettingsClient(context);
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks()
@Override
public void onConnected(@Nullable Bundle bundle)
callback.onGoogleAPIClient(mGoogleApiClient, "Connected");
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(interval);
mLocationRequest.setFastestInterval(fastestInterval);
mLocationRequest.setPriority(priority);
mLocationRequest.setSmallestDisplacement(0);
if (numberOfUpdates > 0) mLocationRequest.setNumUpdates(numberOfUpdates);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
mLocationSettingsRequest = builder.build();
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse ->
showLog("GPS is Enabled Requested Location Update");
requestLocationUpdate();
).addOnFailureListener(e ->
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode)
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try
int REQUEST_CHECK_SETTINGS = 214;
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult((AppCompatActivity) context, REQUEST_CHECK_SETTINGS);
catch (IntentSender.SendIntentException sie)
showLog("Unable to Execute Request");
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
showLog("Location Settings are Inadequate, and Cannot be fixed here. Fix in Settings");
).addOnCanceledListener(new OnCanceledListener()
@Override
public void onCanceled()
showLog("onCanceled");
);
@Override
public void onConnectionSuspended(int i)
connectGoogleClient();
callback.onGoogleAPIClient(mGoogleApiClient, "Connection Suspended");
)
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener()
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
callback.onGoogleAPIClient(mGoogleApiClient, "" + connectionResult.getErrorCode() + " " + connectionResult.getErrorMessage());
)
.addApi(LocationServices.API)
.build();
connectGoogleClient();
mLocationCallback = new LocationCallback()
@Override
public void onLocationResult(final LocationResult locationResult)
super.onLocationResult(locationResult);
Latitude = locationResult.getLastLocation().getLatitude();
Longitude = locationResult.getLastLocation().getLongitude();
if (Latitude == 0.0 && Longitude == 0.0)
showLog("New Location Requested");
requestLocationUpdate();
else
callback.onLocationUpdated(Latitude, Longitude);
;
public LatLng getLastLocation()
if ( ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED )
Location location = mFusedLocationClient.getLastLocation().getResult();
return new LatLng(location.getLatitude(), location.getLongitude());
return null;
@SuppressLint("MissingPermission")
public void removeUpdates()
try
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
callback.onLocationUpdateRemoved();
catch (Exception e)
e.printStackTrace();
private void showLog(String message)
Log.e("LocationProvider", "" + message);
public interface EasyLocationCallback
void onGoogleAPIClient(GoogleApiClient googleApiClient, String message);
void onLocationUpdated(double latitude, double longitude);
void onLocationUpdateRemoved();
public static class Builder
private Context context;
private EasyLocationCallback callback;
private long interval = 10 * 1000;
private long fastestInterval = 5 * 1000;
private int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
private int numberOfUpdates = 0;
public Builder(Context context)
this.context = context;
public LocationProvider build()
if (callback == null)
Toast.makeText(context, "EasyLocationCallback listener can not be null", Toast.LENGTH_SHORT).show();
return new LocationProvider(this);
public Builder setListener(EasyLocationCallback callback)
this.callback = callback;
return this;
public Builder setInterval(long interval)
this.interval = interval;
return this;
public Builder setFastestInterval(int fastestInterval)
this.fastestInterval = fastestInterval;
return this;
public Builder setPriority(int priority)
this.priority = priority;
return this;
public Builder setNumberOfUpdates(int numberOfUpdates)
this.numberOfUpdates = numberOfUpdates;
return this;
设置 locationProvider
locationProvider = new LocationProvider.Builder(MainActivity.this)
.setInterval(10000)
.setFastestInterval(5000)
.setNumberOfUpdates(1) // If you want infinite updates, remove this line entirely
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setListener(new LocationProvider.EasyLocationCallback()
@Override
public void onGoogleAPIClient(GoogleApiClient googleApiClient, String message)
Log.e("LocationProvider", "onGoogleAPIClient: " + message);
@Override
public void onLocationUpdated(double updateLatitude, double updateLongitude)
// You could also add some intelligence to remove the location listener once counter == numberOfUpdates
@Override
public void onLocationUpdateRemoved()
Log.e("LocationProvider", "onLocationUpdateRemoved");
).build();
getLifecycle().addObserver(locationProvider);
【讨论】:
【参考方案4】:以防万一有人为此找到解决方案。您现在可以在 play-services-location 库版本17.1.0
中使用FusedLocationClient.getCurrentLocation
【讨论】:
【参考方案5】:请尝试以下方式使用 FusedLocationProviderClient 获取位置
public class LocationTrackerClient
public static String TAG = LocationTrackerClient.class.getName();
private Location mLastLocation;
LocationRequest mLocationRequest;
private FusedLocationProviderClient mFusedLocationClient;
static Context mcontext;
private static int UPDATE_INTERVAL = 1000;
private static int FATEST_INTERVAL = 1000;
private static int DISPLACEMENT = 5;
private static LocationTrackerClient instance;
private boolean isConnected = false;
public static synchronized LocationTrackerClient getInstance(Context ctx)
mcontext = ctx;
if (instance == null)
instance = new LocationTrackerClient();
return instance;
public void getLocationclient()
try
mFusedLocationClient = null;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mcontext);
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
catch (Exception e)
ExceptionHandler.printStackTrace(e);
public void connectToLocation()
stopLocationUpdates();
getLocationclient();
displayLocation();
public void stopLocationUpdates()
removeFusedLocationUpdate();
public void removeFusedLocationUpdate()
if (Build.VERSION.SDK_INT >= 23)
if (ContextCompat.checkSelfPermission(mcontext,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(mcontext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
else
return;
try
if (mFusedLocationClient != null)
mFusedLocationClient
.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(new OnCompleteListener<Void>()
@Override
public void onComplete(@NonNull Task<Void> task)
Logger.d(TAG, "Location updates stopped at removeFusedLocationUpdate! == ");
// Toast.makeText(getApplicationContext(), "Location updates stopped!", Toast.LENGTH_SHORT).show();
);
catch (Exception e)
e.printStackTrace();
private void displayLocation()
try
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
catch (SecurityException e)
ExceptionHandler.printStackTrace(e);
catch (Exception e)
ExceptionHandler.printStackTrace(e);
private LocationCallback mLocationCallback = new LocationCallback()
@Override
public void onLocationResult(LocationResult locationResult)
super.onLocationResult(locationResult);
Logger.e(TAG, "locationResult ==== " + locationResult);
if (locationResult != null)
mLastLocation = locationResult.getLastLocation();
if (mLastLocation != null)
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
updateLattitudeLongitude(latitude, longitude);
;
public void updateLattitudeLongitude(double latitude, double longitude)
Logger.i(TAG, "updated Lat == " + latitude + " updated long == " + longitude);
SharedPreferenceManager sharedPreferenceManager = SharedPreferenceManager.getInstance();
sharedPreferenceManager.updateUserDeviceLatLong(latitude, longitude);
【讨论】:
以上是关于使用融合的 Location Provider 获取当前位置的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 android 中使用 NETWORK_PROVIDER 时 location.getSpeed() 总是返回 0?
使用 Location Manager 和 Fused Location Provider Api 获取位置有啥区别?
使用 Fused Location Provider 查找位置源