Android 的 FusedLocationApi 不激活 GPS 并返回非常旧的日期

Posted

技术标签:

【中文标题】Android 的 FusedLocationApi 不激活 GPS 并返回非常旧的日期【英文标题】:Android's FusedLocationApi doesn't activate GPS and returns very old dates 【发布时间】:2017-10-23 02:58:50 【问题描述】:

我在一个应用中编写了一些逻辑,用于每 15 分钟采样一次用户的位置。我只对获取用户位置的样本感兴趣,而不是持续跟踪他。

在真实设备上进行测试(启用位置设置)后,我发现我只能在连接到 WiFi 时管理获取位置。但是当我没有连接时(比如走在街上),FusedLocationApi.getLastLocation 函数会返回连接到 WiFi 时采样的旧位置,并且永远不会激活 GPS 来尝试获取真实的当前位置。

虽然我知道我可以过滤掉旧位置,但我不确定如何让 FusedLocationApi 激活 GPS(或至少返回最新位置)。 另一个限制是我不想让 GPS 开启太久,也不想耗尽用户的电量。

在下面的代码中,我连接到 GoogleApiClient 并尝试获取最后一个已知位置。如果此值为空,我会注册以从中获取位置更新,并且一旦获得位置更新(或经过允许的等待时间),我就会断开连接。

我已经对此进行了一整天的测试,FusedLocationApi 不断返回它早上在 WiFi 中采样的旧位置。

/**
 * First function in the location collection chain.
 * This function is called from outside whenever a client wants to get the user's current location.
 */
public void GetCurrentLocation(Context context, final LocationCallbackable callback) 
    currentContext = context;

    // Create an instance of GoogleAPIClient.
    if (mGoogleApiClient == null) 
        mGoogleApiClient = new GoogleApiClient.Builder(context)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    

    // Add the given callback to the callback list. This will be used to return the location to whoever requested it.
    callbacks.add(callback);

    // Connect to GoogleApiClient. When connected, this will trigger onConnected and then we'll be able to request the user's location.
    mGoogleApiClient.connect();


@Override
public void onConnected(@Nullable Bundle bundle) 
    // Create a location request.
    LocationRequest locationRequest = createLocationRequest();

    // Check if we don't have permissions to get fine location.
    if (ActivityCompat.checkSelfPermission(currentContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
        // If we no permissions were granted - call the given callback with null.
        runCallback(null);
        return;
    

    // If we got here, we have permissions :)
    Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (location != null) 
        // Disconnect from GoogleApiClient.
        disconnect();

        // Call the callback that the caller has supplied us with, with the location we have.
        runCallback(location);
    
    // Location was null - that means the GoogleApiClient didn't have enough time to get the current location.
    else 
        // In that case we should check if location settings are valid, and if so register to locationUpdated.
        // If the settings are not valid, we will terminate.
        VerifyLocationSettingsAndContinue(locationRequest);
    


/**
 * Verify if the device's settings are valid for location sampling.
 * If they are - register to get location updates and unregister once we got it.
 * If they are not - the sampling chain is terminated, returning null to the client.
 */
private void VerifyLocationSettingsAndContinue(final LocationRequest locationRequest) 
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
    final LocationManager _this = this;

    // Make sure the user's settings are satisfied.
    PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());

    // Set a callback for the pending result.
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() 
        @Override
        public void onResult(LocationSettingsResult result) 
            final Status status = result.getStatus();
            switch (status.getStatusCode()) 
                case LocationSettingsStatusCodes.SUCCESS:
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, _this);

                    // We can get stuck waiting for an update from FusedLocationApi.requestLocationUpdates.
                    // To solve this, we wait 10 seconds and terminate our self (if we haven't already finished).
                    new android.os.Handler().postDelayed(
                            new Runnable() 
                                public void run() 
                                    // Only try to stop the operation if we didn't get a location update.
                                    if (!isLocationUpdated) 
                                        stopLocationUpdatesAndDisconnect();
                                        runCallback(null);
                                    
                                
                            ,
                            10000);
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                default:
                    // Location settings are not satisfied. Terminate the location sampling by calling the callback with null.
                    disconnect();
                    runCallback(null);
                    break;
            
        
    );


@Override
public void onLocationChanged(Location location) 
    isLocationUpdated = true;
    // We got our location sample - unregister ourselves from requesting location updates and disconnect.
    stopLocationUpdatesAndDisconnect();
    // Call the callback with the location we just got.
    runCallback(location);


private void stopLocationUpdatesAndDisconnect() 
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    disconnect();


private LocationRequest createLocationRequest() 
    final LocationRequest locationRequest = new LocationRequest();
    locationRequest.setInterval(4000);
    locationRequest.setFastestInterval(1000);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set that we only want one update.
    locationRequest.setNumUpdates(1);
    // If we don't get an update, kill the request after 30 seconds.
    locationRequest.setExpirationDuration(30000);

    return locationRequest;

【问题讨论】:

您能否指出您正在学习使用 FusedLocationApi 的资源? 来自Google's Android training,用于获取位置并在线阅读大量内容:) 【参考方案1】:

当您致电getLastKnownLocation 时,您将获得上次获取点时的最后一个已知位置,但不会获取新点。

例如,如果在您的设备上记录的唯一点是在纽约,并且您前往洛杉矶需要 3 天,然后再记录一个新点(通过您的 VerifyLocationSettingsAndContinue 函数),并且您的应用是唯一一个已请求任何积分,那么当您拨打getLastKnownLocation 时,无论您拨打多少次,您都会从纽约获得 3 天前的积分。

为了获得新积分,您必须请求更新位置。

【讨论】:

感谢您的回复。我在调用时没有请求位置更新: LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, _this) ?我还为此添加了一个侦听器函数(onLocationChanged)(它正在被调用但使用旧位置) 感谢您帮助我意识到,如果我没有从 getLastKnownLocation 获得位置,我只会打电话给 requestLocationUpdates。为了解决我的问题,我现在还使用Location.getElapsedRealtimeNanos() 检查位置是否是最新的,如果不是,我会调用requestLocationUpdates 很抱歉在我的帖子中没有提到这一点。很高兴一切顺利!

以上是关于Android 的 FusedLocationApi 不激活 GPS 并返回非常旧的日期的主要内容,如果未能解决你的问题,请参考以下文章

Android游戏开发大全的目录

转Android开发学习总结——搭建最新版本的Android开发环境

Android工程师的概述

Android中常见的权限

Android各个版本的介绍

Android Studio查看Android源码报红