FusedLocationApi.getLastLocation始终为null

时间:2015-04-04 00:17:39

标签: android geolocation location google-play-services

我想在我的Android项目中检索设备位置,为了做到这一点,我使用了播放服务方法:

            protected synchronized void buildGoogleApiClient() {

    mGoogleApiClient = new GoogleApiClient.Builder( MainSearchActivity.this )
        .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
            @Override
            public void onConnected( Bundle bundle ){
                Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                if( location == null ){
                    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, new LocationListener() {
                        @Override
                        public void onLocationChanged(Location location) {
                            lastLocation = location;
                        }
                    });
                }
            }
            @Override
            public void onConnectionSuspended( int i ){

            }

        })
        .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
            @Override
            public void onConnectionFailed( ConnectionResult connectionResult ){
                if( connectionResult.hasResolution() ){
                    try {
                        // Start an Activity that tries to resolve the error
                        connectionResult.startResolutionForResult(MainSearchActivity.this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
                    }catch( IntentSender.SendIntentException e ){
                        e.printStackTrace();
                    }
                }else{
                    Utils.logger("Location services connection failed with code " + connectionResult.getErrorCode(), Utils.LOG_DEBUG );
                }
            }
        })
        .addApi(LocationServices.API)
        .build();

    mGoogleApiClient.connect();
}

public Location retrieveLastLocation(){
    Location loc = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if( loc == null)
    {

    }
    return loc; //TODO: What if loc is null?
}

但是loc变量总是为空。它每次在不同的手机上都是这样的。我尝试在onLocationChanged中分配的lastLocation也永远不会改变。永远为空。

这些是我为应用设置的权限

    <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.vogella.android.locationapi.maps.permission.MAPS_RECEIVE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

我只是不明白:为什么LocationServices无法检索位置?我在所测试的所有三个地方都启用了所有地理定位设置: - /

感谢您的帮助

11 个答案:

答案 0 :(得分:34)

如果至少有一个客户端连接到它,融合Location Provider将仅保留背景位置。现在只需打开位置服务,就无法保证存储最后一个已知位置。

第一个客户端连接后,会立即尝试获取位置。如果您的活动是第一个要连接的客户端,并且getLastLocation()中会立即调用onConnected(),那么第一个位置可能没有足够的时间到达..

我建议您先启动Google地图应用,以便至少有一些确认位置,然后测试您的应用。

答案 1 :(得分:12)

我认为在所显示的代码中我看不到一个小错过。

mGoogleApiClient已构建但似乎未连接。您可以通过调用mGoogleApiClient.isConnected()来验证这一点。

您可以覆盖onStart方法并在那里调用connect。或者,您可以覆盖onResume(),以防每当您的活动可见时都要访问该位置。

  @Override
protected void onStart() {
    super.onStart();
    if (mGoogleApiClient != null) {
        mGoogleApiClient.connect();
    }
}

答案 2 :(得分:10)

首先,创建一个LocationRequest对象:

 // Create the LocationRequest object
 mLocationRequest = LocationRequest.create()
    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
    .setInterval(10 * 1000)        // 10 seconds, in milliseconds
    .setFastestInterval(1 * 1000); // 1 second, in milliseconds

然后,确保用户已授予使用位置的权限。如果是,请从requestLocationUpdates获取位置,如下所示:

void getLocation() {
    Location location = null;
    if (ContextCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);

        /*TODO!! INSERT CODE TO PROMPT USER TO GIVE PERMISSION*/

    } else {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    mLastLocation = location;
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,this);
}

如果您只需要一个没有持续监控的位置,请务必删除更新。这样,您永远不会得到空Location

有关详细信息,请转到http://blog.teamtreehouse.com/beginners-guide-location-android

答案 3 :(得分:6)

正如this帖子所述,融合的位置提供商只会在至少有一个客户端连接到它时才会保留背景位置。

但我们不想启动地图应用以获取最后一个位置,而且我们也无法说我们的用户启动地图应用以获取最后位置。

我们需要做的是

  1. 我们必须从FusedLocationProviderClient
  2. 请求位置更新
  3. 然后我们可以从FusedLocationProviderClient获取最后一个位置,它不会为空。
  4. 请求位置

    LocationRequest mLocationRequest = LocationRequest.create();
    mLocationRequest.setInterval(60000);
    mLocationRequest.setFastestInterval(5000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    LocationCallback mLocationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            for (Location location : locationResult.getLocations()) {
                if (location != null) {
                    //TODO: UI updates.
                }
            }
        }
    };
    LocationServices.getFusedLocationProviderClient(context).requestLocationUpdates(mLocationRequest, mLocationCallback, null);
    

    获取最后一个位置

    LocationServices.getFusedLocationProviderClient(context).getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
            @Override
            public void onSuccess(Location location) {
                //TODO: UI updates.
            }
        });
    

    为了获得有关位置更新的活动请求的最佳结果onStart,您可以获取最后一个位置。

答案 4 :(得分:2)

如果getLastLocation()始终返回null,请尝试此hack。我用它来解决我的问题。在您的活动中实施LocationListener(导入com.google.android.gms.location.LocationListener)。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        Context mContext = this;

        manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);

        createLocationRequest();

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

}

private void createLocationRequest(){
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(SET_INTERVAL);
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}

onStart或onResume(我更喜欢onResume)

@Override
protected void onResume() {
    super.onResume();
    if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) ) {
        if (mGoogleApiClient != null) {
            mGoogleApiClient.connect();
        }
    }else{
        // Showyourmesg();  
    }
}

@Override
protected void onPause() {
    super.onPause();
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
}

protected void startLocationUpdates(){
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
            mLocationRequest,this);
}

protected void stopLocationUpdates() {
    LocationServices.FusedLocationApi.removeLocationUpdates(
            mGoogleApiClient, this);
}

现在,在onLocationChanged方法中检查googleApiClient是否已连接。如果已连接,请断开连接,然后重新连接。

@Override
public void onLocationChanged(Location location) {
    Log.d("SplashAct", "LocatinChngListner, loc: " + location.getLatitude() + "," + location.getLongitude());

    if (mGoogleApiClient != null)
        if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting()){
            mGoogleApiClient.disconnect();
            mGoogleApiClient.connect();
        } else if (!mGoogleApiClient.isConnected()){
            mGoogleApiClient.connect();
        }
}

最后,在你的onConntected()方法中

@Override
  public void onConnected(Bundle bundle) {

    Log.d("ACTIVITY", "ApiClient: OnConnected");

    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
            mGoogleApiClient);

    if (mLastLocation == null){
        startLocationUpdates(); // bind interface if your are not getting the lastlocation. or bind as per your requirement.
    }

    if (mLastLocation != null){
        while (latitude == 0 || longitude == 0){
            pDialog.setMessage("Getting Location");
            pDialog.show();

            latitude = mLastLocation.getLatitude();
            longitude = mLastLocation.getLongitude();

            if (latitude != 0 && longitude != 0){
                stopLocationUpdates(); // unbind the locationlistner here or wherever you want as per your requirement.
                pDialog.dismiss(); // location data received, dismiss dialog, call your method or perform your task.
            }
        }
    }
}

我们反复尝试连接到googleApiClient,即使它已经连接,以便我们可以获取lastLocation数据。这将取决于LocationRequest间隔。您也可以在onLocationChanged中获取位置数据,并从那里执行任务。

答案 5 :(得分:1)

如果您使用的是 Android Marshmallow (API 23)或更新版本的Android,则可能会遇到同样的问题,因为未授予权限。您应该明确request permission at run time获取位置,如果是测试项目,您可以在手机上grant location permission from app settings

答案 6 :(得分:1)

这是确切的答案和解释。

LocationClient getLastLocation() return null

答案 7 :(得分:1)

我的位置为空,我发现模拟器上未安装maps应用。我安装了它并启用了设备位置,然后问题解决了

答案 8 :(得分:0)

这与Amit K. Saha的答案有关,但对我来说,在我的Lollipop个设备上,我一直得到null。所以我打开了地图应用程序,下面的屏幕让我打开所有爵士乐以改善我的位置。

一旦我这样做了一次,我的设备只需拨打一次getLastLocation()就能收到该位置;

我认为,对于可能尚未使用过地图应用的用户,我们必须在应用安装上请求这些权限。

enter image description here

答案 9 :(得分:0)

我正在使用以下代码根据android的最新文档获取位置 https://developer.android.com/training/location/retrieve-current https://developer.android.com/training/location/receive-location-updates

  

MainActivity.java

public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CHECK_SETTINGS = 1;
private static final int REQUEST_GRANT_PERMISSION = 2;
private FusedLocationProviderClient fusedLocationClient;
LocationRequest locationRequest;
private Location currentLocation;
private LocationCallback locationCallback;
Button getUpdates,removeUpdates;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    createLocationRequest();
    settingsCheck();
    getUpdates = findViewById(R.id.button);
    removeUpdates = findViewById(R.id.button2);

    getUpdates.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
                ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_GRANT_PERMISSION);
                return;
            }
            if(locationCallback==null)
                buildLocationCallback();
            if(currentLocation==null)
                fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
        }
    });
    removeUpdates.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
                ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_GRANT_PERMISSION);
                return;
            }
            if(locationCallback!=null)
                fusedLocationClient.removeLocationUpdates(locationCallback);
        }
    });
}

protected void createLocationRequest() {
    locationRequest = LocationRequest.create();
    locationRequest.setInterval(10000);
    locationRequest.setFastestInterval(5000);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

// Check for location settings
public void settingsCheck() {
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest);

    SettingsClient client = LocationServices.getSettingsClient(this);
    Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
    task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
        @Override
        public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
            // All location settings are satisfied. The client can initialize
            // location requests here.
            Log.d("TAG", "onSuccess: settingsCheck");
            getCurrentLocation();
        }
    });

    task.addOnFailureListener(this, new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            if (e instanceof ResolvableApiException) {
                // Location settings are not satisfied, but this can be fixed
                // by showing the user a dialog.
                Log.d("TAG", "onFailure: settingsCheck");
                try {
                    // Show the dialog by calling startResolutionForResult(),
                    // and check the result in onActivityResult().
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(MainActivity.this,
                            REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                }
            }
        }
    });
}

public void getCurrentLocation(){
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
        return;
    }
    fusedLocationClient.getLastLocation()
            .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                @Override
                public void onSuccess(Location location) {
                    Log.d("TAG", "onSuccess: getLastLocation");
                    // Got last known location. In some rare situations this can be null.
                    if (location != null) {
                        currentLocation=location;
                        Log.d("TAG", "onSuccess:latitude "+location.getLatitude());
                        Log.d("TAG", "onSuccess:longitude "+location.getLongitude());
                    }else{
                        Log.d("TAG", "location is null");
                        buildLocationCallback();
                    }
                }
            });
}

private void buildLocationCallback() {
    locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            for (Location location : locationResult.getLocations()) {
                // Update UI with location data
                currentLocation=location;
                Log.d("TAG", "onLocationResult: "+currentLocation.getLatitude());
            }
        };
    };
}

//called after user responds to location permission popup
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode==REQUEST_GRANT_PERMISSION){
        getCurrentLocation();
    }
}
//called after user responds to location settings popup
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Log.d("TAG", "onActivityResult: ");
    if(requestCode==REQUEST_CHECK_SETTINGS && resultCode==RESULT_OK)
        getCurrentLocation();
    if(requestCode==REQUEST_CHECK_SETTINGS && resultCode==RESULT_CANCELED)
        Toast.makeText(this, "Please enable Location settings...!!!", Toast.LENGTH_SHORT).show();
}}
  

XML文件

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.locationexample.MainActivity">

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="88dp"
    android:text="getLocationUpdates"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.502"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="RemoveLocationUpdates"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button"
    app:layout_constraintVertical_bias="0.363" /</android.support.constraint.ConstraintLayout>
  

清单文件

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.locationexample">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

答案 10 :(得分:0)

如果您只想一次定位,或者不想编写locationRequests /回调,请致电

fusedLocationClient
     .requestLocationUpdates(null,null)

在致电之前

fusedLocationClient
     .lastLocation
      .addOnSuccessListener { location ->
                  //get last known location
         }

这将提供即时位置,避免显示空位置。