Android GoogleMaps myLocation Permission

时间:2016-06-23 08:27:02

标签: android google-maps permissions

使用更新版本的Android ...您应该在使用其位置信息之前检查用户是否已经授予您许可。我已经浏览了android文档,这是我提出的代码。

我正在检查用户是否已经给予了许可,如果还没有...那么我们会询问,然后会对结果进行回调功能,依此类推。

我已经多次执行代码并且一切似乎都正常工作除了:当我最终尝试以编程方式使用fusedLocationApi.getLastLocation获取用户的位置时......它返回NULL !! < / p>

我重新上传了我的代码。

任何能够解决这个问题但实际上对我有用的人,你可以拥有我所有的代表得分......

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)

如果我取消注释......这个&#39;这个&#39;用红色加下划线我得到一个错误说&#34; ...在Builder中不能应用于com.example.greg.MapsActivity等&#34;

5 个答案:

答案 0 :(得分:8)

使用ContextCompat.checkSelfPermission检查权限后,如果未授予权限,您可以申请。来自the documentation

此外,您需要在使用GoogleApiClientdocumentation)时处理连接失败。在您的代码中,连接失败,您无法在onConnectionFailed上进行管理。

最后,我从您的代码中删除了以下内容(这导致连接失败,无需使用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();
                }
            }
        }
    }
}

答案 1 :(得分:1)

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

  1. GoogleApiClient是否已连接?
  2. 是否获得许可?
  3. 是否启用了位置?
  4. GoogleMap准备好了吗?
  5. 我建议对每件事使用状态机或布尔值,并且只有当所有四个都为真时才询问位置。例如:

    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));
        }
    }
    
    每次更改其中一个布尔变量时,都会调用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();
    }
    

答案 2 :(得分:1)

我遇到了和你一样的错误。为了节省电池,我想使用 lastKnownLocation 而不是一直轮询。有时, lastKnownLocation 无效,无论我之前检查过什么。

如果您查看文档,可以说:

  

getLastLocation()方法返回一个Location对象,您可以从中检索地理位置的纬度和经度坐标。 在位置不可用的极少数情况下,返回的位置对象可能为null

要解决此问题,我实施了使用 lastKnownLocation 的组合,并轮询新位置作为后备。

我的基本结构是

  1. 检查是否授予了权限
  2. 检查位置是否已启用
  3. 按照in the docs
  4. 所述尝试获取 lastKnownLocation
  5. 如果为null,请求位置更新in this docs example
  6. 这种方法就像一个魅力。到目前为止,我还没有设法找到更好的解决方案,但我建议你试一试。

答案 3 :(得分:0)

此外,检查您是否拥有权限并实际请求它是两回事。

正如android developer blog建议您需要以这样的方式请求权限:

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

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

答案 4 :(得分:0)

这就是问题所在: Android Emulator

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

点击你的电话&#34; (您的模拟器)确保选中它,然后按ctrl + shift + L键入您想要的任何位置,然后单击&#34;发送&#34;和中提琴......你有一个位置。当我的模拟器上的GoogleMaps甚至无法工作时,我知道有些事情发生了。我会搜索方向,它会说&#34;等待位置&#34;什么都不会发生

好吓人的挣脱。