获取当前用户位置或最后已知位置
Get current user location or last known location
我知道这个问题以前被问过很多次,但我现在问这个问题是因为答案很旧(与新的 API 相比)。
我以前用过位置管理器,但我发现它非常不可靠。例如在我的应用程序中,使用 getLastKnownLocation and/or 当前位置,它会立即加载用户当前位置的相机。但是假设我在启动我的应用程序之前就在我的设备上打开了位置,它不会将相机放在用户的当前位置,而是放在尼日拉附近的某个地方(我相信是默认视图)。
只有当我使用 Google 地图应用程序并固定指向我的位置时,或者如果我等待一段时间,我的应用程序才会加载用户在视图中的位置(使用 moveCamera)。
有时它会起作用,有时它不会。但是我想使用 Google Api 客户端,或者更流畅的东西,来检索用户的位置。
我想这样做:
1.) 如果用户没有打开他们的位置,提示他们打开它。
2.) 打开定位功能后,启动地图 camera/view 并以用户当前位置为中心。
3.) 最后,如果用户决定离开位置或离开他们的位置,绝对什么都不做。
我在这里阅读了很多问题,但我找不到任何可以帮助我使用 Google Api 客户端或其他任何东西配置此功能的内容。我已经用位置管理器尝试了几乎所有的东西,但我仍然无法让它顺利工作。出于沮丧,我删除了所有位置管理器代码。
如果你想看看我写下或尝试过的内容,我的大部分资料都来自这个问题(及相关问题):
What is the simplest and most robust way to get the user's current location on Android?
感谢您抽出宝贵时间阅读本文。
位置管理器非常适合我,但对于 API 级别 23,您需要做一些变通办法。 API level 23的权限,需要在主线程中编写权限逻辑。
这是我在我的一个代码中使用的示例。
/*Checking for permission if API level is more than 23 or 23, if condition match function calls*/
if (Build.VERSION.SDK_INT >= 23) {
requestMultiplePermissions();
}
/*Background Thread for splash screen with 2 seconds*/
final Thread splashScreenThread = new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
Intent homeScreen = new Intent(SplashScreen.this, MainActivity.class);
startActivity(homeScreen);
finish();
}
}
};
splashScreenThread.start();
}
/*Standar Permission chcking code for API level 23 or more*/
private void requestMultiplePermissions() {
String locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
int hasLocPermission = checkSelfPermission(locationPermission);
List<String> permissions = new ArrayList<String>();
if (hasLocPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(locationPermission);
}
if (!permissions.isEmpty()) {
String[] params = permissions.toArray(new String[permissions.size()]);
requestPermissions(params, 1);
} else {
// We already have permission, so handle as normal
}
}
/*This is function is used when permissions is granted by user, here we are firing a Intent after getting permission
* */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
Toast.makeText(SplashScreen.this, " " + grantResults, Toast.LENGTH_SHORT).show();
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Handle permission granted firing the Intent
Intent intent = new Intent(SplashScreen.this, MainActivity.class);
startActivity(intent);
finish();
} else {
// Handle permission denied, giving Alertbox to user with some text
new AlertDialog.Builder(this)
.setMessage("The app cannot continue without permissions")
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SplashScreen.this.finish();
}
})
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
//
在您的 Mainactivity 或您想要的任何地方键入以上代码,我更愿意在应用程序启动时请求许可。
以下服务优雅地为我提供了位置服务的准确性和状态。此服务在我登录应用程序之前使用,因为应用程序需要启用定位服务。
基于此服务输入,您可以
- 提示用户开启定位
- 收到位置后,可以启动地图
- 如果location掉线了,处理剩下的逻辑
位置更新要记住的要点是
- 指定接收更新的最小距离变化
setSmallestDisplacement
(API即使我们在一个位置长时间不移动也会取回数据)
- 设置 FastestInterval 以接收位置更新
- 根据您的要求设置优先级参数
setPriority
public class AppLocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener{
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
private Context appContext;
private boolean currentlyProcessingLocation = false;
private int mInterval=0;
private final int CONNTIMEOUT=50000;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
appContext=getBaseContext();
Toast.makeText(getBaseContext(), "Location Service Started", Toast.LENGTH_SHORT)
.show();
if(intent != null){
mInterval = intent.getIntExtra(Constants.REFRESHTIMETAG, 5);
mIMEI = intent.getStringExtra(Constants.IMEITAG);
Log.v(Constants.BLL_LOG, "AppLocationService onStartCommand , mInterval=" + mInterval + " | mIMEI=" + mIMEI);
}
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
startTracking();
}
return START_STICKY;
}
private void startTracking() {
Log.v(Constants.BLL_LOG, "startTracking");
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
Log.v(Constants.BLL_LOG, "ConnectionResult SUCCESS");
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
Log.v(Constants.BLL_LOG, "googleApiClient.connect()");
}else{
Log.v(Constants.BLL_LOG, "NOT connected googleApiClient.connect()");
//
//INTIMATE UI WITH EITHER HANDLER OR RUNONUI THREAD
//
}
} else {
Log.v(Constants.BLL_LOG, "unable to connect to google play services.");
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public AppLocationService() {
}
@Override
public void onConnected(Bundle bundle) {
Log.v(Constants.BLL_LOG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(mInterval * 1000); // milliseconds
locationRequest.setFastestInterval(mInterval * 1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setSmallestDisplacement(MIN_DISTANCE_CHANGE_FOR_UPDATES);//distance change
int permissionCheck = ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION);
if (permissionCheck!= PackageManager.PERMISSION_DENIED)
{ LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(appContext, "Location Service got connected", Toast.LENGTH_SHORT)
.show();
}
});
}
@Override
public void onConnectionSuspended(int i) {
Log.v(Constants.BLL_LOG, "onConnectionSuspended");
//INTIMATE UI ABOUT DISCONNECTION STATUS
}
@Override
public void onLocationChanged(Location location) {
Log.v(Constants.BLL_LOG, "onLocationChanged position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
//if (location.getAccuracy() < 500.0f)
Log.v(Constants.BLL_LOG, "onLocationChanged position: location.getAccuracy()= "+location.getAccuracy());
//DO YOUR BUSINESS LOGIC, FOR ME THE SAME WAS TO SEND TO SERVER
sendLocationDataToWebsite(location);
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.v(Constants.BLL_LOG, "onConnectionFailed");
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(appContext, "Location Service got disconnected temporarily", Toast.LENGTH_SHORT)
.show();
}
});
}
/**
* Send details to server
* @param location
*/
void sendLocationDataToWebsite(Location location){
}
@Override
public void onDestroy() {
super.onDestroy();
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
this.unregisterReceiver(this.batteryInfoReceiver);
}
}
注意:此服务仍需要在更新版本中进行测试
我知道这个问题以前被问过很多次,但我现在问这个问题是因为答案很旧(与新的 API 相比)。
我以前用过位置管理器,但我发现它非常不可靠。例如在我的应用程序中,使用 getLastKnownLocation and/or 当前位置,它会立即加载用户当前位置的相机。但是假设我在启动我的应用程序之前就在我的设备上打开了位置,它不会将相机放在用户的当前位置,而是放在尼日拉附近的某个地方(我相信是默认视图)。
只有当我使用 Google 地图应用程序并固定指向我的位置时,或者如果我等待一段时间,我的应用程序才会加载用户在视图中的位置(使用 moveCamera)。
有时它会起作用,有时它不会。但是我想使用 Google Api 客户端,或者更流畅的东西,来检索用户的位置。
我想这样做:
1.) 如果用户没有打开他们的位置,提示他们打开它。
2.) 打开定位功能后,启动地图 camera/view 并以用户当前位置为中心。
3.) 最后,如果用户决定离开位置或离开他们的位置,绝对什么都不做。
我在这里阅读了很多问题,但我找不到任何可以帮助我使用 Google Api 客户端或其他任何东西配置此功能的内容。我已经用位置管理器尝试了几乎所有的东西,但我仍然无法让它顺利工作。出于沮丧,我删除了所有位置管理器代码。
如果你想看看我写下或尝试过的内容,我的大部分资料都来自这个问题(及相关问题):
What is the simplest and most robust way to get the user's current location on Android?
感谢您抽出宝贵时间阅读本文。
位置管理器非常适合我,但对于 API 级别 23,您需要做一些变通办法。 API level 23的权限,需要在主线程中编写权限逻辑。
这是我在我的一个代码中使用的示例。
/*Checking for permission if API level is more than 23 or 23, if condition match function calls*/
if (Build.VERSION.SDK_INT >= 23) {
requestMultiplePermissions();
}
/*Background Thread for splash screen with 2 seconds*/
final Thread splashScreenThread = new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
Intent homeScreen = new Intent(SplashScreen.this, MainActivity.class);
startActivity(homeScreen);
finish();
}
}
};
splashScreenThread.start();
}
/*Standar Permission chcking code for API level 23 or more*/
private void requestMultiplePermissions() {
String locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
int hasLocPermission = checkSelfPermission(locationPermission);
List<String> permissions = new ArrayList<String>();
if (hasLocPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(locationPermission);
}
if (!permissions.isEmpty()) {
String[] params = permissions.toArray(new String[permissions.size()]);
requestPermissions(params, 1);
} else {
// We already have permission, so handle as normal
}
}
/*This is function is used when permissions is granted by user, here we are firing a Intent after getting permission
* */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
Toast.makeText(SplashScreen.this, " " + grantResults, Toast.LENGTH_SHORT).show();
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Handle permission granted firing the Intent
Intent intent = new Intent(SplashScreen.this, MainActivity.class);
startActivity(intent);
finish();
} else {
// Handle permission denied, giving Alertbox to user with some text
new AlertDialog.Builder(this)
.setMessage("The app cannot continue without permissions")
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SplashScreen.this.finish();
}
})
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
//
在您的 Mainactivity 或您想要的任何地方键入以上代码,我更愿意在应用程序启动时请求许可。
以下服务优雅地为我提供了位置服务的准确性和状态。此服务在我登录应用程序之前使用,因为应用程序需要启用定位服务。
基于此服务输入,您可以
- 提示用户开启定位
- 收到位置后,可以启动地图
- 如果location掉线了,处理剩下的逻辑
位置更新要记住的要点是
- 指定接收更新的最小距离变化
setSmallestDisplacement
(API即使我们在一个位置长时间不移动也会取回数据) - 设置 FastestInterval 以接收位置更新
- 根据您的要求设置优先级参数
setPriority
public class AppLocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener{
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
private Context appContext;
private boolean currentlyProcessingLocation = false;
private int mInterval=0;
private final int CONNTIMEOUT=50000;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
appContext=getBaseContext();
Toast.makeText(getBaseContext(), "Location Service Started", Toast.LENGTH_SHORT)
.show();
if(intent != null){
mInterval = intent.getIntExtra(Constants.REFRESHTIMETAG, 5);
mIMEI = intent.getStringExtra(Constants.IMEITAG);
Log.v(Constants.BLL_LOG, "AppLocationService onStartCommand , mInterval=" + mInterval + " | mIMEI=" + mIMEI);
}
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
startTracking();
}
return START_STICKY;
}
private void startTracking() {
Log.v(Constants.BLL_LOG, "startTracking");
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
Log.v(Constants.BLL_LOG, "ConnectionResult SUCCESS");
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
Log.v(Constants.BLL_LOG, "googleApiClient.connect()");
}else{
Log.v(Constants.BLL_LOG, "NOT connected googleApiClient.connect()");
//
//INTIMATE UI WITH EITHER HANDLER OR RUNONUI THREAD
//
}
} else {
Log.v(Constants.BLL_LOG, "unable to connect to google play services.");
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public AppLocationService() {
}
@Override
public void onConnected(Bundle bundle) {
Log.v(Constants.BLL_LOG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(mInterval * 1000); // milliseconds
locationRequest.setFastestInterval(mInterval * 1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setSmallestDisplacement(MIN_DISTANCE_CHANGE_FOR_UPDATES);//distance change
int permissionCheck = ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION);
if (permissionCheck!= PackageManager.PERMISSION_DENIED)
{ LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(appContext, "Location Service got connected", Toast.LENGTH_SHORT)
.show();
}
});
}
@Override
public void onConnectionSuspended(int i) {
Log.v(Constants.BLL_LOG, "onConnectionSuspended");
//INTIMATE UI ABOUT DISCONNECTION STATUS
}
@Override
public void onLocationChanged(Location location) {
Log.v(Constants.BLL_LOG, "onLocationChanged position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
//if (location.getAccuracy() < 500.0f)
Log.v(Constants.BLL_LOG, "onLocationChanged position: location.getAccuracy()= "+location.getAccuracy());
//DO YOUR BUSINESS LOGIC, FOR ME THE SAME WAS TO SEND TO SERVER
sendLocationDataToWebsite(location);
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.v(Constants.BLL_LOG, "onConnectionFailed");
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(appContext, "Location Service got disconnected temporarily", Toast.LENGTH_SHORT)
.show();
}
});
}
/**
* Send details to server
* @param location
*/
void sendLocationDataToWebsite(Location location){
}
@Override
public void onDestroy() {
super.onDestroy();
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
this.unregisterReceiver(this.batteryInfoReceiver);
}
}
注意:此服务仍需要在更新版本中进行测试