LocationClient getLastLocation()返回null

时间:2013-05-30 07:12:23

标签: android gps location

就像之前遇到的问题一样 我测试了一个nexus s(4.0.4提供谷歌播放服务)和avd(4.2.2 with google api),在这两种情况下,locationclient getLastLocation()总是返回null

public class MainActivity extends Activity implements LocationListener,
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener {

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
    boolean mUpdatesRequested = false;
    boolean mConnected = false;
    SharedPreferences mPrefs;
    SharedPreferences.Editor mEditor;
    private TextView mText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mText = (TextView) findViewById(R.id.text);
        mLocationRequest = LocationRequest.create();
        mLocationRequest
                .setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest
.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);
        mUpdatesRequested = false;
        mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES,
                Context.MODE_PRIVATE);
        mEditor = mPrefs.edit();
        mLocationClient = new LocationClient(this, this, this);
    }
    @Override
    public void onStart() {
        super.onStart();
        /*
         * Connect the client. Don't re-start any requests here; instead, wait
         * for onResume()
         */
        mLocationClient.connect();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // If the app already has a setting for getting location updates, get it
        if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
            mUpdatesRequested = mPrefs.getBoolean(
                    LocationUtils.KEY_UPDATES_REQUESTED, false);
            // Otherwise, turn off location updates until requested
        } else {
            mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
            mEditor.commit();
        }
    }
    @Override
    public void onStop() {
        // If the client is connected
        if (mLocationClient.isConnected()) {
            stopPeriodicUpdates();
        }
        // After disconnect() is called, the client is considered "dead".
        mLocationClient.disconnect();
        super.onStop();
    }

    @Override
    public void onPause() {
        // Save the current setting for updates
        mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED,
                mUpdatesRequested);
        mEditor.commit();
        super.onPause();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    public void getLocation(View v) {
        // If Google Play Services is available
        if (isGooglePlayServicesAvailable()) {
            if (!mConnected)
                mText.setText("location client is not connected to service yet");
            else {
                // Get the current location
                Location currentLocation = mLocationClient.getLastLocation();
                // Display the current location in the UI
                mText.setText(LocationUtils.getLocationString(currentLocation));
            }
        }
    }

    private boolean isGooglePlayServicesAvailable() {

        // Check that Google Play services is available
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(this);

        // If Google Play services is available
        if (ConnectionResult.SUCCESS == resultCode) {
            // In debug mode, log the status
            Log.d(LocationUtils.APPTAG, "google play service is available");

            // Continue
            return true;
            // Google Play services was not available for some reason
        } else {
            // Display an error dialog
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode,
                    this, 0);
            if (dialog != null) {
                Log.e(LocationUtils.APPTAG,
                        "google play service is unavailable");
            }
            return false;
        }
    }

    private void stopPeriodicUpdates() {
        mLocationClient.removeLocationUpdates(this);
        // mConnectionState.setText(R.string.location_updates_stopped);
    }

    @Override
    public void onConnectionFailed(ConnectionResult arg0) {
        mConnected = false;
        Log.d(LocationUtils.APPTAG, "connection failed");
    }

    @Override
    public void onConnected(Bundle arg0) {
        mConnected = true;
        Log.d(LocationUtils.APPTAG,
                "location client connected to the location server");
        LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0,
                new android.location.LocationListener() {
                    @Override
                    public void onStatusChanged(String provider, int status,
                            Bundle extras) {}

                    @Override
                    public void onProviderEnabled(String provider) {}

                    @Override
                    public void onProviderDisabled(String provider) {}

                    @Override
                    public void onLocationChanged(final Location location) {
                    }
                });
        Log.d(LocationUtils.APPTAG, "done trying to get location");
    }

    @Override
    public void onDisconnected() {
        // TODO Auto-generated method stub
        mConnected = false;
        Log.d(LocationUtils.APPTAG,
                "location client disconnected from the location server");
    }

    @Override
    public void onLocationChanged(Location arg0) {}

}

其中大多数来自谷歌提供的示例。在上面的代码中,hava尝试了这样的方法:

LocationRequest request = LocationRequest.create();
request.setNumUpdates(1);
mLocationClient.requestLocationUpdates(request, this);

LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0,
                new android.location.LocationListener() {
                    @Override
                    public void onStatusChanged(String provider, int status,Bundle extras) {}

                    @Override
                    public void onProviderEnabled(String provider) {}

                    @Override
                    public void onProviderDisabled(String provider) {}

                    @Override
                    public void onLocationChanged(final Location location) {}
                });

在调用onConnected()之前getLastLocation(),但仍然没有运气。 哪里是错误,提前谢谢。

13 个答案:

答案 0 :(得分:50)

目前Fused Location Provider仅在至少有一个客户端连接到它时才会维护后台位置。一旦第一个客户端连接,它将立即尝试获取位置。如果您的活动是第一个要连接的客户,并且您在getLastLocation()中立即致电onConnected(),则可能没有足够的时间让第一个地点进入。

答案 1 :(得分:21)

按照the tutorial的说明操作时遇到同样的问题。 在手机上它工作,并在(Genymotion)模拟器它没有。

解决方案

在AndroidManifest.xml中,更改此内容:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

到此:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

......然后你马上就到了。无需更改代码(收听位置更新)。

答案 2 :(得分:19)

您的设备未启用“Wi-Fi和移动网络位置”也可能导致此问题。

LocationClient(融合位置提供商)使用GPS和WiFi。 GPS需要一段时间才能找到您的位置,而wifi速度要快得多。但是,如果连接了这两个服务中的任何一个,则将调用onConnected的回调方法。如果您尝试立即在onConnected方法中调用LocationClient.getLastLocation(),那么如果您的wifi位置服务被禁用,则很可能会获得空值。这只是因为GPS不够快。

要在本地解决此问题,请启用“Wi-Fi和移动网络位置”。您可以转到“设置&gt;个人&gt;位置访问&gt; Wi-Fi和移动网络位置”来执行此操作。

但是,如果要解决应用程序用户的问题,最好检查getLastLocation()是否返回null。如果是,请提示您的用户启用该服务,就像谷歌地图一样。

希望这有帮助。

答案 3 :(得分:7)

我遇到了类似的问题。

mLocationClient.getLastLocation()中或在建立与Google Play服务的连接后致电onConnected。如果您在连接位置客户端之前调用此方法,则返回的位置将为null

您可以通过mLocationClient.isConnected()检查位置客户端是否已连接。

希望这有帮助。

答案 4 :(得分:5)

您必须检查用户是否通过Wi-Fi / GSM或GPS启用了位置。如果没有任何可用的位置提供商,则会获得null

此代码显示包含位置设置的屏幕:

startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));

答案 5 :(得分:5)

这是完全有效的解决方案,可能在不同的情况下。但我想添加一些解释步骤,以便任何人都能获得确切的概念:

1)Android组件的onCreate()(例如,活动片段服务注意:不是IntentService ),构建,然后连接 GoogleApiClient,如下所示。

buildGoogleApiClient();
mGoogleApiClient.connect();

其中,buildGoogleApiClient()实现是,

protected synchronized void buildGoogleApiClient() {
        Log.i(TAG, "Building GoogleApiClient");

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

    }

稍后在onDestroy()上,您可以将GoogleApiClient与

断开连接
@Override
    public void onDestroy() {
        Log.i(TAG, "Service destroyed!");
        mGoogleApiClient.disconnect();
        super.onDestroy();
    }

第1步确保您构建并连接GoogleApiClient。

1)GoogleApiClient实例第一次在方法onConnected()上连接。现在,您的下一步应该是onConnected()方法。

@Override
    public void onConnected(@Nullable Bundle bundle) {
        Log.i(TAG, "GoogleApiClient connected!");
        buildLocationSettingsRequest();
        createLocationRequest();
        location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        Log.i(TAG, " Location: " + location); //may return **null** because, I can't guarantee location has been changed immmediately 
    }

上面,您调用方法 createLocationRequest()来创建位置请求。方法 createLocationRequest()如下所示。

protected void createLocationRequest() {
        //remove location updates so that it resets
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); //Import should not be **android.Location.LocationListener**
    //import should be **import com.google.android.gms.location.LocationListener**;

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        //restart location updates with the new interval
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);

    }

3)现在,在LocationListener接口的onLocationChange()回调中,您将获得新位置。

@Override
    public void onLocationChanged(Location location) {
        Log.i(TAG, "Location Changed!");
        Log.i(TAG, " Location: " + location); //I guarantee,I get the changed location here

    }

您可以在Logcat中获得如下结果: 03-22 18:34:17.336 817-817 / com.LiveEarthquakesAlerts I / LocationTracker:位置:位置[fuse 37.421998,-122.084000 acc = 20 et = + 15m35s840ms alt = 0.0]

为了能够执行这三个步骤,您应该已经配置了build.gradle,如下所示:

 compile 'com.google.android.gms:play-services-location:10.2.1'

答案 6 :(得分:4)

我在使用三星手机(高度自定义的Android,没有开发人员支持)的测试中遇到了类似的问题。

LocationManager和LocationClient不会从提供商那里获得GPS。每当您需要它们的位置时,它们都需要启动。在LocationManager.getLastKnownLocationLocationClient.getLastLocation来电之前执行此操作。这些API将返回。

YOUR_APPLICATION_CONTEXT.getLocationManager().requestLocationUpdates(
    LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
        @Override
        public void onProviderEnabled(String provider) {
        }
        @Override
        public void onProviderDisabled(String provider) {
        }
        @Override
        public void onLocationChanged(final Location location) {
        }
    });

答案 7 :(得分:3)

在SDK版本23

您还需要在运行时明确请求位置权限 https://developer.android.com/training/permissions/requesting.html 以及将它放在清单文件中。

如果您在运行时没有权限,则不会发生显式错误,位置提供程序将只返回null。

如果Google记录了这一点,它会有所帮助,并且还会抛出异常,而不仅仅是返回null。在这种情况下,返回null是最不利的事情。

答案 8 :(得分:2)

我的应用程序也遇到了同样的问题,唯一缺少的是应用程序只请求了ACCESS_COARSE_LOCATION而不是ACCESS_FINE_LOCATION。 我添加了后来的权限,一切正常。

答案 9 :(得分:0)

谷歌播放服务地理定位无法在没有互联网连接的情况下工作,对GPS无动于衷。因此,请检查打开移动数据的应用。

答案 10 :(得分:0)

您只需要该位置的更新请求。如果有26个Android SDK权限就可以了:

private void setLocation(Context context) {
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
            .addApi(LocationServices.API).build();
    googleApiClient.connect();

     locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(2000);
    locationRequest.setFastestInterval(2000);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
    builder.setAlwaysShow(true);
    PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
        @Override
        public void onResult(LocationSettingsResult result) {
            final Status status = result.getStatus();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                    showMessage(" All location settings are satisfied.");
                    mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
                            .addApi(LocationServices.API)
                            .addConnectionCallbacks(connectionCallbacks)
                            .addOnConnectionFailedListener(connectionFailedListener)
                            .build();
                            mGoogleApiClient.connect();
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    l.a(" Location settings are not satisfied. Show the user a dialog to upgrade location settings ");

                    try {
                        // Show the dialog by calling startResolutionForResult(), and check the result
                        // in onActivityResult().
                        status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
                    } catch (IntentSender.SendIntentException e) {
                        showMessage("PendingIntent unable to execute request.");
                    }
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    showMessage("Location settings are inadequate, and cannot be fixed here. Dialog not created.");
                    break;
            }
        }
    });
}

并在onConnected回调方法中:

 @Override
    public void onConnected(@Nullable Bundle bundle) {
        l.a(3232);
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) !=
                PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                   return;
        }

            mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                    mGoogleApiClient);
       if(null==mLastLocation){//  !!!!!!!!!!!! here it can happen !!!!!!!

                    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, new LocationListener() {
                        @Override
                        public void onLocationChanged(Location location) {
                            mLastLocation = location;
                            locationWasFound = true;
                            sevumPora.setLocation(mLastLocation);
                            mGoogleApiClient.disconnect();
                        }
                    });
                return;
            }
        locationWasFound = true;
        sevumPora.setLocation(mLastLocation);
        mGoogleApiClient.disconnect();
    }

答案 11 :(得分:-1)

我在Nexus 7设备上运行并完美运行。 你们错误地写了旧版本的LocationListener,它没有用于新的API。

您必须使用新的LocationListener进行设置。

您需要导入此类,然后尝试。

import com.google.android.gms.location.LocationListener;

它根据新API覆盖了唯一一种方法

@Override
public void onLocationChanged(final Location newLocation) 
{}

请尝试这种方式,如果您仍然遇到任何问题,请告诉我。

感谢。

答案 12 :(得分:-3)

最简单的解决办法,虽然减慢了一点,但是使用辅助函数。我的问题是它会连接,但在找到一个位置之前,我会尝试访问它并点击一个空指针。

public Location getLocation(LocationClient locationClient){

    if(locationClient.getLastLocation() == null){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getLocation(locationClient);
    }else{
        return locationClient.getLastLocation();
    }
}

只需在onConnected中使用此功能,并设置您想要使用此功能的位置,并传递您的位置客户端。

@Override
public void onConnected(Bundle dataBundle) {

    Location temp = getLocation(mLocationClient);
    mLocation = temp;
}

此外,如果您因某种原因不想从onConnected获取位置,只要您通过locationClient,就可以在任何地方使用相同的辅助功能。