我们已经推出了一款利用GPS信息的Android应用程序,而我们的少数用户报告说,GPS对他们不起作用。虽然我们已经投入了大量的时间来改进代码库,但是我们仍然无法为受影响的用户提供相关的改进。我们现在正在寻找新的想法,从社区向前迈进一步,解决这个问题。提前感谢您的反馈!
在我们的Android应用程序中,我们通过三个连续步骤来识别用户的位置:
-
当前GPS位置(GPS提供程序)
-
当前网络位置(网络提供商)
-
最后一个已知的GPS位置(GPS提供程序)
如果一个步骤失败,则尝试下一个步骤。如果没有任何步骤成功,则会向用户显示GPS错误消息。
问题
少数用户报告说
总是
接收GPS错误信息。我们与用户一起尝试了以下操作,但没有成功:
-
确保设备上已启用GPS
-
确保为应用程序授予GPS权限(细粒度位置)
-
关闭应用程序,获取谷歌地图上的当前位置,然后重新启动应用程序
代码
这是我们的代码。应用程序调用地理位置.getCurrentLocation(..).
public class GeoRepository {
private static final String TAG = GeoRepository.class.getSimpleName();
public GeoRepository() {
}
public class GeoNoPermissionException extends RuntimeException {
public GeoNoPermissionException(String message, Throwable cause) {
super(message, cause);
}
}
public class GeoNoLocationException extends RuntimeException {
public GeoNoLocationException(String message, Throwable cause) {
super(message, cause);
}
}
public interface GeoLocationListener {
void onCompleted(Location location);
void onFailed(RuntimeException ex);
}
public void getCurrentLocation(Context context, GeoLocationListener listener) {
// The permissions for this is already being requested in the SplashActivity
boolean hasPermission = !(ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
listener.onFailed(new GeoNoPermissionException("Missing permissions", null));
return;
}
// try initially with precise GPS provider
requestLocationOnce(context, LocationManager.GPS_PROVIDER, new GeoLocationListener() {
@Override
public void onCompleted(Location location) {
listener.onCompleted(location);
}
@Override
public void onFailed(RuntimeException ex) {
Log.e(TAG, "Could not find location on first attempt", ex);
requestLocationOnce(context, LocationManager.NETWORK_PROVIDER, new GeoLocationListener() {
@Override
public void onCompleted(Location location) {
listener.onCompleted(location);
}
@Override
public void onFailed(RuntimeException ex) {
Log.e(TAG, "Could not find location on second attempt", ex);
Location location = null;
try {
location = requestLastKnownLocation(context, LocationManager.GPS_PROVIDER);
} catch(RuntimeException ex2) {
Log.e(TAG, "Could not find location on third attempt", ex2);
/* !!! this is where we hit the wall and return a GPS-errormessage to the user !!! */
listener.onFailed(ex);
return;
}
if(location == null) {
Log.e(TAG, "Could not find location on third attempt, location is null");
listener.onFailed(ex);
return;
}
listener.onCompleted(location);
}
});
}
});
}
private void requestLocationOnce(Context context, String provider, GeoLocationListener listener) {
// The permissions for this is already being requested in the SplashActivity
boolean hasPermission = !(ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
listener.onFailed(new GeoNoPermissionException("Missing permissions", null));
return;
}
Object syncObj = new Object();
CountDownLatch completedSignal = new CountDownLatch(1);
LocationManager locationManager = (LocationManager) FlourishApp.getContext().getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// this method may never get called hence we need a watchdog later on
// this happens for example if GPS permissions are there but GPS is turned off
synchronized(syncObj) {
if (completedSignal.getCount() > 0) {
completedSignal.countDown();
listener.onCompleted(location);
}
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
locationManager.requestSingleUpdate(
provider,
locationListener,
Looper.getMainLooper());
new Handler(Looper.getMainLooper()).postDelayed(() -> {
// cleanup event subscription
locationManager.removeUpdates(locationListener);
// watchdog to raise error if we don't get a callback within reasonable time
boolean receivedLocationUpdate = true;
synchronized (syncObj) {
if (completedSignal.getCount() > 0) {
completedSignal.countDown();
receivedLocationUpdate = false;
}
}
if(!receivedLocationUpdate) {
GeoNoLocationException ex = new GeoNoLocationException("No location could be determined", null);
listener.onFailed(ex);
}
}, Constants.LOCATION_MAX_WAIT); // LOCATION_MAX_WAIT = 50000
}
private Location requestLastKnownLocation(Context context, String provider) {
// The permissions for this is already being requested in the SplashActivity
boolean hasPermission = !(ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
throw new GeoNoPermissionException("Missing permissions", null);
}
LocationManager locationManager = (LocationManager) FlourishApp.getContext().getSystemService(Context.LOCATION_SERVICE);
return locationManager.getLastKnownLocation(provider);
}
public interface GetCountryCodeByCurrentLocationListener {
void onCompleted(String countryCode);
void onFailed(RuntimeException ex);
}
}
设备
受影响的用户一直在使用以下设备之一:
-
华为P8
-
Oppo CPH1723公司
-
银河笔记4
思想
-
会不会是因为用户只是离线才导致了这个问题?这不应该被排除在谷歌地图测试和利用最后已知的位置。
-
-
应用程序权限是否应该受到指责?没有这一点已经向用户澄清。
-
我们的代码有问题吗?也许,但我们无法确定任何明显的缺陷。
-
你试过其他的供应商吗?是的,我们也尝试了新的融合位置提供者API,同样的问题也发生了。
有什么想法吗?谢谢你的帮助!