FusedLocationApi.getLastLocation 始终为空

FusedLocationApi.getLastLocation always null

我只想在我的 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 变量始终为空。每次都在不同的手机上如此。另外 lastLocation,我尝试在 onLocationChanged 中分配,永远不会改变。始终为空。

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

<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 无法检索位置?我在我测试过的所有三台设备上都启用了所有地理定位设置。

融合 Location Provider 只有在至少有一个客户端连接到它时才会保持后台位置。现在仅仅打开定位服务并不能保证存储最后已知的位置。

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

我建议你先启动地图应用,这样至少有一些确认的位置,然后再测试你的应用。

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

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

您可以覆盖 onStart 方法并在那里调用连接。或者您可以覆盖 onResume(),以防您希望在您的 activity 可见时访问该位置。

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

如果 getLastLocation() 始终返回 null,请尝试此 hack。我用它来解决我的问题。在 activity.

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

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

一旦我这样做了一次,我的设备就能够通过一次调用 getLastLocation();

来接收位置

我想,对于那些可能还没有使用过他们的地图应用程序的用户来说,他们必须在安装应用程序时请求这些权限。

首先,创建一个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

如果您使用的是 Android Marshmallow (API 23) 或更新版本的 Android,您可能会遇到同样的问题,因为 未授予权限。您应该在 phone.

上明确 request permission at run time for location or, if it's a test project you can grant location permission from app settings

这里是准确的答案和解释。

LocationClient getLastLocation() return null

正如 post 所说,如果至少有一个客户端连接到它,融合的位置提供者将只维护后台位置。

但我们可以跳过启动 Google 地图应用程序的过程,通过以下方式获取最后位置。

我们需要做的是

  1. 我们必须从 FusedLocationProviderClient
  2. 请求位置更新
  3. 然后我们可以从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.
        }
    });

为获得最佳结果,请在 Activity 的 onStart() 中请求位置更新,然后您可以获得最后一个位置。

我正在使用以下代码根据 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 file

<?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>

Manifest File

<?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>

要发出单个位置请求,您可以使用

方法一->getCurrentLocation()

cancellationTokenSource = CancellationTokenSource()

val currentLocationTask = LocationServices
        .getFusedLocationProviderClient(requireContext()).getCurrentLocation(
            LocationRequest.PRIORITY_HIGH_ACCURACY,
            cancellationTokenSource.token
        )

您可以使用

取消请求
cancellationTokenSource.cancel()

方法二->setNumUpdates(1)

mLocationRequest
        .setNumUpdates(1)

我的位置信息为空,我发现模拟器上没有安装地图应用程序。我安装了它并启用了设备位置,然后问题解决了

我安装了一个具有 google 播放服务并且可以运行的模拟器

Android - 科特林

If you need to get user location in android, I am using this my function and suggest it:

// Get user location after getting permission.
private fun findUserLocation() {

    if (ActivityCompat.checkSelfPermission(requireContext(),
            Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(requireContext(),
            Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Check location permission. Some one is missing.
    }
    else {
        val locationRequest = LocationRequest.create() // Create location request.
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY // Set priority.

        val locationCallback: LocationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                for (location in locationResult.locations) {
                    if (location != null) {

                        // TODO: Show your code here. 
                        // Such as:
                        val lat = location.latitude  
                        val lon = location.longitude
                    }
                }
            }
        }

        // Create a location provider client and send request for getting location.
        val client = LocationServices.getFusedLocationProviderClient(requireContext())
        client.requestLocationUpdates(locationRequest, locationCallback, null)
    }
}