由于运行时问题,Google Maps API 无法在 API 23 以上运行

Posted

技术标签:

【中文标题】由于运行时问题,Google Maps API 无法在 API 23 以上运行【英文标题】:Google Maps API not working above API 23 due to run time issues 【发布时间】:2017-09-23 10:31:19 【问题描述】:

问题:Maps API 在 API 23 下运行良好,但由于运行时问题,它们在第一次运行时无法以某种方式获得权限。他们第一次请求权限,但第一次不工作。当我第二次运行该应用程序时,它在 23 以上的 API 上也能正常工作。但是对于第一次运行,它不起作用。这段代码应该做什么以及第二次做什么,是要求用户一个一个地放置两个标记,并使用用户选择的坐标对其进行反向地理编码。

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
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.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import java.io.IOException;
import java.util.List;
import java.util.Locale;


public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener 

    private GoogleMap mMap;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;
    LocationRequest mLocationRequest;
    public Button homeLocationFromPin;
    public Button officeLocationFromPin;
    public static double homeLatitude;
    public static double officeLatitude;
    public static double homeLongitude;
    public static double officeLongitude;
    public int count = 0;
    public MarkerOptions placedHomeMarker;
    public MarkerOptions placedOfficeMarker;
    public static final int LOCATION_REQUEST_CODE = 99;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);

        if (ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission
                (this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 

            requestPermission(Manifest.permission.ACCESS_FINE_LOCATION,
                    LOCATION_REQUEST_CODE);
        



        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(map);
        mapFragment.getMapAsync(this);

        homeLocationFromPin = (Button) findViewById(R.id.confirmHomeLocation);
        homeLocationFromPin.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                if (String.valueOf(homeLongitude) != null && String.valueOf(homeLatitude) != null) 
                    //Get nearby Places here based on Latitude and Longitude
//                    Toast.makeText(MapsActivity.this, getAddress(homeLatitude, homeLongitude), Toast.LENGTH_LONG).show();
                    showAlertBoxForHomeLocationConfirmation(getAddress(homeLatitude, homeLongitude));
                 else 
                    Toast.makeText(MapsActivity.this, "Please drop pin to home location first", Toast.LENGTH_SHORT).show();
                
            
        );


        officeLocationFromPin = (Button) findViewById(R.id.confirmOfficeLocation);
        officeLocationFromPin.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                if (String.valueOf(officeLatitude) != null && String.valueOf(officeLongitude) != null) 
                    //Get nearby Places here based on Latitude and Longitude
//                    Toast.makeText(MapsActivity.this, getAddress(homeLatitude, homeLongitude), Toast.LENGTH_LONG).show();
                    showAlertBoxForOfficeLocationConfirmation(getAddress(officeLatitude, officeLongitude));
                 else 
                    Toast.makeText(MapsActivity.this, "Please drop pin to home location first", Toast.LENGTH_SHORT).show();
                
            
        );


    //End Of OnCreate

    @Override
    public void onMapReady(GoogleMap googleMap) 
        mMap = googleMap;
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        LatLng boston = new LatLng(42.3601, -71.0589);
        mMap.moveCamera(CameraUpdateFactory.newLatLng(boston));
        mMap.animateCamera(CameraUpdateFactory.zoomTo(15));

        showAlertBox("Home");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 

            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) 
                buildGoogleApiClient();
                mMap.setMyLocationEnabled(true);
                Toast.makeText(this, "Inside Perm", Toast.LENGTH_LONG).show();
                mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() 
                    @Override
                    public void onMapClick(LatLng latLng) 

                        if (count == 0) 
                            //Make the confirm button available on first tap
                            homeLocationFromPin.setVisibility(View.VISIBLE);
                            //add(point);
                            mMap.clear();
                            placedHomeMarker = new MarkerOptions().position(latLng);
                            placedHomeMarker.title("Home Location");
                            mMap.addMarker(placedHomeMarker);
                            homeLatitude = latLng.latitude;
                            homeLongitude = latLng.longitude;
                            Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                         else 
                            officeLocationFromPin.setVisibility(View.VISIBLE);
                            placedOfficeMarker = new MarkerOptions().position(latLng);
                            placedOfficeMarker.title("Office Location");
                            mMap.addMarker(placedOfficeMarker);
                            officeLatitude = latLng.latitude;
                            officeLongitude = latLng.longitude;
                            Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                            Toast.makeText(MapsActivity.this, getNameOnly(officeLatitude, officeLongitude), Toast.LENGTH_SHORT).show();
                        
                    
                );
             else 

            buildGoogleApiClient();
            mMap.setMyLocationEnabled(true);
            mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() 
                @Override
                public void onMapClick(LatLng latLng) 
                    if (count == 0) 
                        //Make the confirm button available on first tap
                        homeLocationFromPin.setVisibility(View.VISIBLE);
                        //add(point);
                        mMap.clear();
                        placedHomeMarker = new MarkerOptions().position(latLng);
                        placedHomeMarker.title("Home Location");
                        mMap.addMarker(placedHomeMarker);
                        homeLatitude = latLng.latitude;
                        homeLongitude = latLng.longitude;
                        Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                     else 
                        officeLocationFromPin.setVisibility(View.VISIBLE);
                        placedOfficeMarker = new MarkerOptions().position(latLng);
                        placedOfficeMarker.title("Office Location");
                        mMap.addMarker(placedOfficeMarker);
                        officeLatitude = latLng.latitude;
                        officeLongitude = latLng.longitude;
                        Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                        Toast.makeText(MapsActivity.this, getNameOnly(officeLatitude, officeLongitude), Toast.LENGTH_SHORT).show();
                    
                
            );
        
        
    //End of onMap Ready

    protected synchronized void buildGoogleApiClient() 
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    

    @Override
    public void onConnected(Bundle bundle) 

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) 
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        
    

    @Override
    public void onConnectionSuspended(int i) 

    


    @Override
    public void onLocationChanged(Location location) 

        mLastLocation = location;
        if (mCurrLocationMarker != null) 
            mCurrLocationMarker.remove();
        

        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
//        markerOptions.title("Your Current Location");
//        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
//        markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.home));
//        markerOptions.draggable(true);
        mCurrLocationMarker = mMap.addMarker(markerOptions);

        //move map camera
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mMap.animateCamera(CameraUpdateFactory.zoomTo(15));

        //Set a marker drag listener
        mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() 
            @Override
            public void onMarkerDragStart(Marker marker) 

            

            @Override
            public void onMarkerDrag(Marker marker) 

            

            @Override
            public void onMarkerDragEnd(Marker marker) 
                mMap.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()));
                //Get the latitude and longitude of the place where user dropped the marker
                Toast.makeText(MapsActivity.this, "Latitude:" + String.valueOf(marker.getPosition().latitude), Toast.LENGTH_LONG).show();
                homeLatitude = marker.getPosition().latitude;
                Toast.makeText(MapsActivity.this, "Longitude:" + String.valueOf(marker.getPosition().longitude), Toast.LENGTH_LONG).show();
                homeLongitude = marker.getPosition().longitude;

            
        );


        //stop location updates
        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        

    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 
    


    public void showAlertBox(String LocationName) 

        AlertDialog.Builder b1 = new AlertDialog.Builder(MapsActivity.this);
        b1.setMessage("Please select your " + LocationName + " location.\nTap anywhere on the screen to select your "
                + LocationName +
                "location and press button to confirm.");
        b1.setCancelable(false);

        b1.setPositiveButton("Ok",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 

                    
                );

        AlertDialog customAlertBox = b1.create();
        customAlertBox.show();

    


    public void showAlertBoxForHomeLocationConfirmation(String reverseGeoStr) 

        AlertDialog.Builder b1 = new AlertDialog.Builder(MapsActivity.this);
        b1.setMessage("Confirm your home location or search again\n" + reverseGeoStr);
        b1.setCancelable(false);

        b1.setPositiveButton("Confirm",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        count = 3;

                        homeLocationFromPin.setVisibility(View.GONE);
                        showAlertBox("Office");
                    
                );

        b1.setNegativeButton("Do it again",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        Toast.makeText(MapsActivity.this, "Place Pin Again", Toast.LENGTH_SHORT).show();
                    
                );
        AlertDialog customAlertBox = b1.create();
        customAlertBox.show();

    


    public void showAlertBoxForOfficeLocationConfirmation(String reverseGeoStr) 

        AlertDialog.Builder b1 = new AlertDialog.Builder(MapsActivity.this);
        b1.setMessage("Confirm your Office location or search again\n" + reverseGeoStr);
        b1.setCancelable(false);

        b1.setPositiveButton("Confirm",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        Intent st = new Intent(MapsActivity.this, getUserName.class);
                        startActivity(st);
                        finish();
                    
                );

        b1.setNegativeButton("Do it again",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        Toast.makeText(MapsActivity.this, "Place Pin Again", Toast.LENGTH_SHORT).show();
                    
                );
        AlertDialog customAlertBox = b1.create();
        customAlertBox.show();

    


    private String getAddress(double latitude, double longitude) 
        if (latitude == 0.0 || longitude == 0.0) 
            //Give default values so it does not returns null
            latitude = 42.3601;
            longitude = -71.0589;
        
        StringBuilder result = new StringBuilder();
        try 
            Geocoder geocoder = new Geocoder(this, Locale.getDefault());
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (addresses.size() > 0) 
                Address address = addresses.get(0);
                result.append(address.getAddressLine(0)).append("\n");
                result.append(address.getLocality()).append("\n");
                result.append(address.getAdminArea()).append("\n");
                result.append(address.getPostalCode()).append("\n");
                result.append(address.getCountryName());
            
         catch (IOException e) 
            Log.e("tag", e.getMessage());
        

        return result.toString();
    

    private String getNameOnly(double latitude, double longitude) 
        if (latitude == 0.0 || longitude == 0.0) 
            //Give default values so it does not returns null
            latitude = 42.3601;
            longitude = -71.0589;
        
        StringBuilder result = new StringBuilder();
        try 
            Geocoder geocoder = new Geocoder(this, Locale.getDefault());
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (addresses.size() > 0) 
                Address address = addresses.get(0);
                result.append(address.getAddressLine(0)).append("\n");
                result.append(address.getLocality()).append("\n");
            
         catch (IOException e) 
            Log.e("tag", e.getMessage());
        
        return result.toString();
    


    protected void requestPermission(String permissionType, int requestCode) 
        int permission = ContextCompat.checkSelfPermission(this,
                permissionType);

        if (permission != PackageManager.PERMISSION_GRANTED) 
            ActivityCompat.requestPermissions(this,
                    new String[]permissionType, requestCode
            );
        
    

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) 
        switch (requestCode) 
            case LOCATION_REQUEST_CODE: 

                if (grantResults.length == 0
                        || grantResults[0] != PackageManager.PERMISSION_GRANTED) 
                    Toast.makeText(this, "Unable to show location - permission required", Toast.LENGTH_LONG).show();
                
                return;
            
        
    


【问题讨论】:

【参考方案1】:

当您在onMapReady() 请求位置更新时,您应该在onRequestPermissionsResult 方法中调用mapFragment.getMapAsync(this);

public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) 
        switch (requestCode) 
            case LOCATION_REQUEST_CODE: 
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) 

                    mapFragment.getMapAsync(this);


                 else 
                    Toast.makeText(getApplicationContext(), "Please provide the permission", Toast.LENGTH_LONG).show();
                
                break;
            
         

希望这会有所帮助。

【讨论】:

看起来合乎逻辑并且正在工作。谢谢。这么小的事情我一直在敲打我的头,好几个小时。非常感谢。 真的很高兴它有帮助。 :)【参考方案2】:

上面的解决方案使它适用于 API > 23 的手机,但它停止使用 API

   @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) 
        switch (requestCode) 
            case LOCATION_REQUEST_CODE: 

                if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) 
                    Toast.makeText(this, "Unable to show location - permission required", Toast.LENGTH_LONG).show();
                    return;
                

//                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
//                    mapFragment.getMapAsync(this);
//                
                else
                
                    Toast.makeText(this,"Permission not granted",Toast.LENGTH_LONG).show();
                
                break;
            
        
    


在 onMapReady() 中

@Override
public void onMapReady(GoogleMap googleMap) 
    mMap = googleMap;
    mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    LatLng boston = new LatLng(42.3601, -71.0589);
    mMap.moveCamera(CameraUpdateFactory.newLatLng(boston));
    mMap.animateCamera(CameraUpdateFactory.zoomTo(15));

    showAlertBox("Home");

    if (ActivityCompat.checkSelfPermission
            (this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED

            && ActivityCompat.checkSelfPermission
            (this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) 

        mMap.setMyLocationEnabled(true);

     else 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            requestPermission(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_REQUEST_CODE);
        
    


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 

        buildGoogleApiClient();
        Toast.makeText(this, "Inside Perm", Toast.LENGTH_LONG).show();
        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() 
            @Override
            public void onMapClick(LatLng latLng) 

                if (count == 0) 
                    //Make the confirm button available on first tap
                    homeLocationFromPin.setVisibility(View.VISIBLE);
                    //add(point);
                    mMap.clear();
                    placedHomeMarker = new MarkerOptions().position(latLng);
                    placedHomeMarker.title("Home Location");
                    mMap.addMarker(placedHomeMarker);
                    homeLatitude = latLng.latitude;
                    homeLongitude = latLng.longitude;
                    Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                 else 
                    officeLocationFromPin.setVisibility(View.VISIBLE);
                    placedOfficeMarker = new MarkerOptions().position(latLng);
                    placedOfficeMarker.title("Office Location");
                    mMap.addMarker(placedOfficeMarker);
                    officeLatitude = latLng.latitude;
                    officeLongitude = latLng.longitude;
                    Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                    Toast.makeText(MapsActivity.this, getNameOnly(officeLatitude, officeLongitude), Toast.LENGTH_SHORT).show();
                
            
        );
     else 

        buildGoogleApiClient();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) 
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            mMap.setMyLocationEnabled(true);
        

        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() 
            @Override
            public void onMapClick(LatLng latLng) 
                if (count == 0) 
                    //Make the confirm button available on first tap
                    homeLocationFromPin.setVisibility(View.VISIBLE);
                    //add(point);
                    mMap.clear();
                    placedHomeMarker = new MarkerOptions().position(latLng);
                    placedHomeMarker.title("Home Location");
                    mMap.addMarker(placedHomeMarker);
                    homeLatitude = latLng.latitude;
                    homeLongitude = latLng.longitude;
                    Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                 else 
                    officeLocationFromPin.setVisibility(View.VISIBLE);
                    placedOfficeMarker = new MarkerOptions().position(latLng);
                    placedOfficeMarker.title("Office Location");
                    mMap.addMarker(placedOfficeMarker);
                    officeLatitude = latLng.latitude;
                    officeLongitude = latLng.longitude;
                    Toast.makeText(MapsActivity.this, getNameOnly(homeLatitude, homeLongitude), Toast.LENGTH_SHORT).show();
                    Toast.makeText(MapsActivity.this, getNameOnly(officeLatitude, officeLongitude), Toast.LENGTH_SHORT).show();
                
            
        );
    
//End of onMap Ready

【讨论】:

是的,上面的解决方案专门针对您提到的问题。预计提问者将根据需要进行额外的修改。这不会使答案错误。尽管有许多方法可以为所有“API”版本使用上述代码,但你的方法非常好,赞成票也是我的。干杯! 我没有说错。我非常感谢您的帮助。我也赞成你的回答。再次感谢。

以上是关于由于运行时问题,Google Maps API 无法在 API 23 以上运行的主要内容,如果未能解决你的问题,请参考以下文章

无法运行 Google Maps Android API Utility Demo

在 PhoneGap iOS App 中使用 Google Maps JavaScript API v3

为啥我的 Google Maps API 请求在服务器上运行时不起作用

Google Places API 中缺少 Google Maps 中的地点

Google Maps API v3 中的 Javascript 错误 (RefererDeniedMapError)

Google Maps API:强制放大到特定位置