由于运行时问题,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 以上运行的主要内容,如果未能解决你的问题,请参考以下文章