Android GoogleMaps myLocation权限

随着更新版本的Android …你应该检查用户是否给你的权限,然后再使用他们的位置信息。 我已经通过了Android文档,这是我已经提出的代码。

我正在检查用户是否已经给予权限,如果他们还没有…那么我们问,然后有一个callback函数的结果等等。

我已经通过代码多次,一切似乎工作正常除了:当我终于尝试以编程方式获取用户的位置fusedLocationApi.getLastLocation …它返回NULL!

我已经重新上传了我的代码。

任何人都可以看出来,它实际上适用于我,你可以有我所有的代表分数…

package com.example.greg.rightnow; import android.content.pm.PackageManager; import android.location.Location; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentActivity; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.Manifest; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.Api; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.Status; import com.google.android.gms.drive.Drive; import com.google.android.gms.location.LocationServices; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.plus.Plus; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.concurrent.TimeUnit; public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, ConnectionCallbacks { private GoogleApiClient mGoogleApiClient; private GoogleMap mMap; private Location mLastLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); // Create an instance of GoogleAPIClient. mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addApi(Plus.API) .addScope(Drive.SCOPE_FILE) .addConnectionCallbacks(this) // .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } @Override public void onConnected(@Nullable Bundle bundle) { } protected void onStart() { mGoogleApiClient.connect(); super.onStart(); } protected void onStop() { mGoogleApiClient.disconnect(); super.onStop(); } /** * Manipulates the map once available. * This callback is triggered when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. In this case, * we just add a marker near Sydney, Australia. * If Google Play services is not installed on the device, the user will be prompted to install * it inside the SupportMapFragment. This method will only be triggered once the user has * installed Google Play services and returned to the app. * Manifest.permission.ACCESS_FINE_LOCATION */ @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == grantResults[0]) { mMap.setMyLocationEnabled(true); } mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); LatLng myLat = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); // Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mMap.moveCamera(CameraUpdateFactory.newLatLng(myLat)); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == 0) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); } else if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) ==-1) { mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); LatLng myLat = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); // Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mMap.moveCamera(CameraUpdateFactory.newLatLng(myLat)); } } @Override public void onConnectionSuspended(int i) { } } 

你会注意到我必须注释掉这一行:

  // .addOnConnectionFailedListener(this) 

如果我取消注释这个…“this”以红色加下划线,我得到一个错误说“…在生成器不能应用于com.example.greg.MapsActivity等”

Solutions Collecting From Web of "Android GoogleMaps myLocation权限"

通过ContextCompat.checkSelfPermission检查权限后,如果没有被授予,您可以请求它。 从文档 :

另外,使用GoogleApiClient ( 文档 )时,您需要处理连接失败。 在你的代码中,连接失败,你不在onConnectionFailed上进行pipe理。

最后,我从你的代码中删除了下面的代码(这导致了连接失败,并且不需要使用LocationServices并获取最后的位置):

 .addApi(Drive.API) .addApi(Plus.API) .addScope(Drive.SCOPE_FILE) 

这是一个工作的例子:

 public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static final int FINE_LOCATION_PERMISSION_REQUEST = 1; private static final int CONNECTION_RESOLUTION_REQUEST = 2; private GoogleApiClient mGoogleApiClient; private GoogleMap mMap; private Location mLastLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); buildGoogleAPIClient(); } @Override protected void onResume() { super.onResume(); buildGoogleAPIClient(); } private void buildGoogleAPIClient() { if (mGoogleApiClient == null) { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } } @Override public void onConnected(@Nullable Bundle bundle) { findLocation(); } protected void onStart() { mGoogleApiClient.connect(); super.onStart(); } protected void onStop() { mGoogleApiClient.disconnect(); super.onStop(); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; } @Override public void onConnectionSuspended(int i) { Toast.makeText(this, "Connection suspended", Toast.LENGTH_SHORT).show(); } @Override public void onConnectionFailed(@NonNull final ConnectionResult connectionResult) { if (connectionResult.hasResolution()) { try { connectionResult.startResolutionForResult(this, CONNECTION_RESOLUTION_REQUEST); } catch (IntentSender.SendIntentException e) { // There was an error with the resolution intent. Try again. mGoogleApiClient.connect(); } } else { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 1); dialog.show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CONNECTION_RESOLUTION_REQUEST && resultCode == RESULT_OK) { mGoogleApiClient.connect(); } } private void findLocation() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, FINE_LOCATION_PERMISSION_REQUEST); } else { mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); LatLng myLat = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); // Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mMap.moveCamera(CameraUpdateFactory.newLatLng(myLat)); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case FINE_LOCATION_PERMISSION_REQUEST: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { findLocation(); } } } } } 

我和你一样面对同样的错误。 为了省电,我想使用lastKnownLocation而不是一直轮询。 有时, lastKnownLocation为null,不pipe我以前检查过什么。

如果你看看这个文档,可以这样说:

getLastLocation()方法返回一个Location对象,您可以从中检索地理位置的纬度和经度坐标。 当位置不可用时,返回的位置对象可能为空

为了解决这个问题,我实现了使用lastKnownLocation和轮询新位置作为后备的组合。

我这里的基本结构是

  1. 检查是否授予权限
  2. 检查位置是否启用
  3. 尝试按文档中所述获取lastKnownLocation
  4. 如果为空,请在此文档示例中请求位置更新

这种方法就像一个魅力。 到目前为止,我还没有find一个更好的解决scheme,但我build议你去尝试一下。

此外,检查是否有权限并实际请求是两个不同的事情。

正如Android开发者博客build议您需要以这样的方式请求权限:

 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_RESULT_CODE); 

然后通过覆盖onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)处理请求的结果。

在获取最后一个已知位置之前,您需要检查四件事情:

  1. GoogleApiClient是否连接?
  2. 是否授予许可?
  3. 是位置启用?
  4. GoogleMap准备好了吗?

我build议每个事物都使用状态机或布尔型,并且只有在四个条件都成立的情况下才会询问位置。 例如:

 protected void getLastKnownLocationIfReady(){ if(isGoogleApiConnected && isPermissionGranted && isLocationEnabled && isGoogleMapReady){ mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); LatLng myLat = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); // Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mMap.moveCamera(CameraUpdateFactory.newLatLng(myLat)); } } 

每次更改其中一个布尔variables时都调用getLastKnownLocationIfReady()函数。

所以你的onConnected看起来像例如:

 @Override public void onConnected(@Nullable Bundle bundle) { isGoogleApiConnected = true; getLastKnownLocationIfReady(); } 

检查权限如:

  if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, FINE_LOCATION_PERMISSION_REQUEST); } else { isPermissionGranted = true; getLastKnownLocationIfReady(); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case FINE_LOCATION_PERMISSION_REQUEST: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { isPermissionGranted = true; getLastKnownLocationIfReady(); } } } } 

你可以要求启用的位置,如:

 public void requestLocationAccess(){ if(mLocationRequest == null) createLocationRequest(); final LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest); builder.setAlwaysShow(true); //this is the key ingredient com.google.android.gms.common.api.PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build()); result.setResultCallback(new ResultCallback<LocationSettingsResult>(){ @Override public void onResult(@NonNull LocationSettingsResult result){ final Status resultStatus = result.getStatus(); switch(resultStatus.getStatusCode()){ case LocationSettingsStatusCodes.SUCCESS: // All location settings are satisfied. isLocationEnabled = true; getLastKnownLocationIfReady(); break; case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: // Location settings are not satisfied. But could be fixed by showing the user a dialog. You need to override OnActivityResult if you want to handle the user's interaction with the dialog. resultStatus.startResolutionForResult(this, REQUEST_LOCATION); break; default: break; } } }); } 

修改你的onMapReady如:

 @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; isGoogleMapReady = true; getLastKnownLocationIfReady(); } 

这里有问题: Android模拟器

向下滚动到“使用扩展控件,设置和帮助”。
长话短说:如果你使用仿真器,你必须伪造你的位置数据!!!!! 模拟器不支持WiFi(或者据我所知,GPS数据也是)。

点击你的“手机”(你的模拟器),以确保它被选中,然后按Ctrl + Shift + L键入任何你想要的位置,然后点击“发送”和中提琴…你将有一个位置。 当我的模拟器上的GoogleMaps甚至不能正常工作时,我知道一些事情已经结束了。 我会search方向,它会说“等待位置”,什么都不会发生。

好吓人的脱落。