使用 FusedLocationProviderClient 请求位置更新不起作用,永远不会调用回调
Requesting location updates using FusedLocationProviderClient is not working, callback is never called
我正在尝试使用 Firebase
云消息传递向我的 Android 应用程序发送命令,提示它确定其当前 location
。这是在 class FCMService
.
中完成的
class SingleShotLocationProvider
然后通过使用 FusedLocationProviderClient
请求 location
更新来执行实际工作。然而,回调 fusedTrackerCallback
永远不会被调用,尽管必要的 permissions
被授予并且 GPS
被打开。为什么?
FCMService class
public class FCMService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("FCMService", "Message received");
if(remoteMessage.getData().containsKey("command") && remoteMessage.getData().get("command").equalsIgnoreCase("locate")) {
// get current location
SingleShotLocationProvider locProv = new SingleShotLocationProvider(getApplicationContext());
locProv.requestSingleUpdate();
System.out.println("Requested single location update.");
}
}
}
}
SingleShotLocationProvider class
public class SingleShotLocationProvider {
private Context context;
final LocationManager locManager;
private FusedLocationProviderClient mFusedLocationClient;
private LocationCallback fusedTrackerCallback;
public SingleShotLocationProvider(Context context) {
this.context = context;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
locManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE );
if (locManager != null && !locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Log.e("SiSoLocProvider", "GPS IS NOT enabled.");
} else {
Log.d("SiSoLocProvider", "GPS is enabled.");
}
}
@TargetApi(16)
public void requestSingleUpdate() {
Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback(){
@Override
public void onLocationResult(LocationResult locationResult) {
if((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime+30*1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime+30*1000));
}
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, null);
}
}
输出为:
//Message received
//GPS is enabled.
//Permission granted.
//Requested single location update.
但仅此而已。为什么?可能是因为 permission
是通过 service application context
授予的?
根据你的代码,我猜你想在后台线程中获取位置并接收结果。这是一个解决方案。
@TargetApi(16)
public void requestSingleUpdate() {
// TODO: Comment-out this line.
// Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
// TODO: Start a background thread to receive location result.
final HandlerThread handlerThread = new HandlerThread("RequestLocation");
handlerThread.start();
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
// TODO: Those lines of code will run on the background thread.
if ((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime + 30 * 1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime + 30 * 1000));
}
// TODO: After receiving location result, remove the listener.
mFusedLocationClient.removeLocationUpdates(this);
// Release the background thread which receive the location result.
handlerThread.quit();
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
// TODO: Pass looper of background thread indicates we want to receive location result in a background thread instead of UI thread.
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, handlerThread.getLooper());
}
如果您想在 UI 线程上接收位置结果。
@TargetApi(16)
public void requestSingleUpdate() {
// TODO: Comment-out this line.
// Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
// TODO: These lines of code will run on UI thread.
if ((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime + 30 * 1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime + 30 * 1000));
}
// TODO: After receiving location result, remove the listener.
mFusedLocationClient.removeLocationUpdates(this);
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
// Receive location result on UI thread.
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, Looper.getMainLooper());
}
我添加了以 TODO:
关键字开头的每个评论来解释我的意图。
我正在尝试使用 Firebase
云消息传递向我的 Android 应用程序发送命令,提示它确定其当前 location
。这是在 class FCMService
.
class SingleShotLocationProvider
然后通过使用 FusedLocationProviderClient
请求 location
更新来执行实际工作。然而,回调 fusedTrackerCallback
永远不会被调用,尽管必要的 permissions
被授予并且 GPS
被打开。为什么?
FCMService class
public class FCMService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("FCMService", "Message received");
if(remoteMessage.getData().containsKey("command") && remoteMessage.getData().get("command").equalsIgnoreCase("locate")) {
// get current location
SingleShotLocationProvider locProv = new SingleShotLocationProvider(getApplicationContext());
locProv.requestSingleUpdate();
System.out.println("Requested single location update.");
}
}
}
}
SingleShotLocationProvider class
public class SingleShotLocationProvider {
private Context context;
final LocationManager locManager;
private FusedLocationProviderClient mFusedLocationClient;
private LocationCallback fusedTrackerCallback;
public SingleShotLocationProvider(Context context) {
this.context = context;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
locManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE );
if (locManager != null && !locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Log.e("SiSoLocProvider", "GPS IS NOT enabled.");
} else {
Log.d("SiSoLocProvider", "GPS is enabled.");
}
}
@TargetApi(16)
public void requestSingleUpdate() {
Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback(){
@Override
public void onLocationResult(LocationResult locationResult) {
if((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime+30*1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime+30*1000));
}
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, null);
}
}
输出为:
//Message received
//GPS is enabled.
//Permission granted.
//Requested single location update.
但仅此而已。为什么?可能是因为 permission
是通过 service application context
授予的?
根据你的代码,我猜你想在后台线程中获取位置并接收结果。这是一个解决方案。
@TargetApi(16)
public void requestSingleUpdate() {
// TODO: Comment-out this line.
// Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
// TODO: Start a background thread to receive location result.
final HandlerThread handlerThread = new HandlerThread("RequestLocation");
handlerThread.start();
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
// TODO: Those lines of code will run on the background thread.
if ((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime + 30 * 1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime + 30 * 1000));
}
// TODO: After receiving location result, remove the listener.
mFusedLocationClient.removeLocationUpdates(this);
// Release the background thread which receive the location result.
handlerThread.quit();
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
// TODO: Pass looper of background thread indicates we want to receive location result in a background thread instead of UI thread.
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, handlerThread.getLooper());
}
如果您想在 UI 线程上接收位置结果。
@TargetApi(16)
public void requestSingleUpdate() {
// TODO: Comment-out this line.
// Looper.prepare();
// only works with SDK Version 23 or higher
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// permission is not granted
Log.e("SiSoLocProvider", "Permission not granted.");
return;
} else {
Log.d("SiSoLocProvider", "Permission granted.");
}
} else {
Log.d("SiSoLocProvider", "SDK < 23, checking permissions should not be necessary");
}
final long startTime = System.currentTimeMillis();
fusedTrackerCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
// TODO: These lines of code will run on UI thread.
if ((locationResult.getLastLocation() != null) && (System.currentTimeMillis() <= startTime + 30 * 1000)) {
System.out.println("LOCATION: " + locationResult.getLastLocation().getLatitude() + "|" + locationResult.getLastLocation().getLongitude());
System.out.println("ACCURACY: " + locationResult.getLastLocation().getAccuracy());
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
} else {
System.out.println("LastKnownNull? :: " + (locationResult.getLastLocation() == null));
System.out.println("Time over? :: " + (System.currentTimeMillis() > startTime + 30 * 1000));
}
// TODO: After receiving location result, remove the listener.
mFusedLocationClient.removeLocationUpdates(this);
}
};
LocationRequest req = new LocationRequest();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setFastestInterval(2000);
req.setInterval(2000);
// Receive location result on UI thread.
mFusedLocationClient.requestLocationUpdates(req, fusedTrackerCallback, Looper.getMainLooper());
}
我添加了以 TODO:
关键字开头的每个评论来解释我的意图。