FusedLocationApi.getLastLocation始终为null

问题描述 投票:35回答:9

我想在我的Android项目中简单地检索设备位置,为了做到这一点,我使用了play-services方法:

            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不能检索一个位置?我在测试的所有三个设备上启用了所有地理定位设置: - /

感谢您的任何帮助

android geolocation location google-play-services
9个回答
35
投票

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

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

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


13
投票

我想在我看到的代码中有一个小小的遗漏。

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

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

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

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);
}

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

有关更多信息,请访问http://blog.teamtreehouse.com/beginners-guide-location-android


8
投票

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

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

我们需要做的是

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

请求位置

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,您可以获取最后一个位置。


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中获取位置数据,并从那里执行任务。


1
投票

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


1
投票

这是确切的答案和解释。

LocationClient getLastLocation() return null


0
投票

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

一旦我做了一次,我的设备只需拨打一次getLastLocation()即可获得该位置;

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

enter image description here


0
投票

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

main activity.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>

© www.soinside.com 2019 - 2024. All rights reserved.