使用 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: 关键字开头的每个评论来解释我的意图。