63

就像有人在我测试 nexus s(4.0.4 with google play service available) 和 avd (4.2.2 with google api) 之前遇到的问题一样,在这两种情况下 locationclientgetLastLocation()总是 return 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(),但仍然没有运气。哪里出错了,先谢谢了。

4

13 回答 13

56

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

于 2013-05-31T22:17:04.577 回答
22

按照教程中的说明进行操作时,我遇到了同样的问题。在电话上它可以工作,而在(Genymotion)模拟器上它没有。

解决方案

在您的 AndroidManifest.xml 中,更改以下内容:

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

对此:

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

...您立即获得位置。无需更改您的代码(收听位置更新)。

于 2013-10-26T10:47:26.810 回答
20

该问题也可能是由于您的设备未启用“Wi-Fi 和移动网络位置”造成的。

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

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

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

希望这会有所帮助。

于 2013-09-16T13:26:17.843 回答
7

我面临着类似的问题。

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

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

希望这可以帮助。

于 2013-06-26T14:13:08.273 回答
6

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

LocationManager 和 LocationClient 不会从提供商那里获得 GPS。每次您需要它们的位置时,都需要启动它们。在您的LocationManager.getLastKnownLocationORLocationClient.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) {
        }
    });
于 2013-06-01T03:55:26.033 回答
6

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

1) Android 组件的 onCreate() (例如,ActivityFragmentService注意:不是 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: Location: Location[fused 37.421998,-122.084000 acc=20 et=+15m35s840ms alt=0.0]

为了能够完成这三个步骤,您应该如下配置您的 build.gradle:

 compile 'com.google.android.gms:play-services-location:10.2.1'
于 2017-03-22T23:47:13.920 回答
5

您必须检查用户是否已通过 Wi-Fi/GSM 或 GPS 启用定位。如果没有任何可用的位置提供程序,您将获得null.

此代码显示带有位置设置的屏幕:

startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
于 2013-05-30T12:13:29.010 回答
3

在 SDK 版本 23 上

您还需要在运行时明确请求位置权限,根据 https://developer.android.com/training/permissions/requesting.html 以及清单文件中的内容。

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

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

于 2016-08-27T16:00:09.043 回答
2

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

于 2013-09-06T16:45:25.260 回答
1

您只需要对该位置的更新请求。如果有 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();
    }
于 2017-11-18T15:28:44.610 回答
0

我运行并且它在 Nexus 7 设备中完美运行。你们错误地写了旧版本的 LocationListener ,它没有与新的 API 一起使用。

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

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

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

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

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

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

谢谢。

于 2013-07-30T05:13:56.590 回答
0

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

于 2013-08-28T07:39:29.153 回答
-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.

于 2014-07-10T23:34:53.573 回答