You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Marshmallow+ Google Maps我的位置层首次启动不显示问题

问题根因

首次启动不显示定位图层、重启后恢复正常,是典型的时序问题,两个点叠加导致故障:

  • SupportMapFragment在你调用findFragmentById的时候就已经开始异步加载地图,不会等权限申请流程走完。用户还在看权限弹窗的时候,地图就可能已经加载完成触发onMapReady回调,此时权限未授予,你在回调里调用setMyLocationEnabled(true)会直接触发安全异常,被你加的@SuppressWarnings("all")全量压制吞掉报错,定位图层根本没启用成功。
  • 用户点击同意授权后,你虽然再次调用了getMapAsync,但已经初始化完成的GoogleMap实例在不少SDK版本下不会重复走完整的onMapReady初始化逻辑,之前因为权限不足没开成的定位图层不会自动重试,自然看不到。重启应用时权限已经是预授予状态,onMapReady触发时权限检查直接通过,图层就能正常加载。

另外你把INTERNET这种安装时自动授予的普通权限加到运行时申请列表里,属于多余操作,不需要动态申请。

修复方案

按以下步骤调整代码即可:

  • 把INTERNET权限从运行时申请的权限数组中移除,仅在Manifest中声明即可。
  • 新增独立的定位图层启用方法,不要把图层启用逻辑完全绑定在onMapReady回调里,不管是地图加载完成还是权限申请通过,只要条件满足就调用该方法检查并启用图层。
  • 权限申请通过后,先判断GoogleMap实例是否已经存在,如果存在直接尝试启用图层,不用等重复的onMapReady回调。
  • 所有调用位置敏感API的位置都补上显式权限检查,不要靠注解压制吞掉异常。
  • 补全位置获取的空判断,避免特殊情况下getLastLocation返回null触发空指针。
关键修改代码

首先调整initData中的权限数组:

private void initData() {
    // 移除不需要动态申请的INTERNET权限
    PERMISSIONS = new String[]{
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
    };

    googleMap = null;
    currentLocation = null;
    mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

新增独立的图层启用方法:

private void enableMyLocationLayer() {
    // 先检查权限,权限不足直接返回
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    if (googleMap == null) {
        // 地图未就绪,等onMapReady触发后会再次调用该方法
        return;
    }
    // 权限、地图实例都就绪后再开启图层
    googleMap.setMyLocationEnabled(true);
    // 图层开启后再获取当前位置、缩放视角
    getLastLocation();
}

调整onMapReady逻辑,不要直接硬编码开启图层:

@Override
public void onMapReady(@NonNull GoogleMap googleMap) {
    Toast.makeText(this, "Start OnMapReady", Toast.LENGTH_LONG).show();
    this.googleMap = googleMap;
    this.googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);

    this.googleMap.setOnMyLocationButtonClickListener(this);
    this.googleMap.setOnMyLocationClickListener(this);
    this.googleMap.getUiSettings().setZoomControlsEnabled(true);

    this.googleMap.setOnMapClickListener(latLng -> {
        Toast.makeText(MainActivity.this, "Click on " + latLng, Toast.LENGTH_SHORT).show();
        this.googleMap.addMarker(new MarkerOptions().position(latLng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
    });

    // 统一走图层启用方法
    enableMyLocationLayer();
}

调整权限申请回调,权限通过后直接尝试启用图层:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    boolean permissionsAreAccepted = true;
    if (requestCode == LOCATION_PERMISSION_REQUEST_CODE && grantResults.length > 0) {
        for (int grantResult : grantResults) {
            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                permissionsAreAccepted = false;
                break;
            }
        }
        if (permissionsAreAccepted) {
            // 权限到手先直接尝试开图层,地图已就绪的话会立刻生效
            enableMyLocationLayer();
            // 地图还没初始化完成的话,再触发地图加载回调
            if (googleMap == null) {
                mapFragment.getMapAsync(this);
            }
        } else {
            askLocationPermission();
        }
    }
}

补全getLastLocation的权限检查和空判断:

private void getLastLocation() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    Task<Location> locationTask = mFusedLocationClient.getLastLocation();
    locationTask.addOnSuccessListener(location -> {
        if (location == null) {
            Toast.makeText(this, "暂时无法获取当前位置,请检查设备定位开关", Toast.LENGTH_SHORT).show();
            return;
        }
        currentLocation = location;
        zoomOnCurrentPlace();
    });
}

额外修复:你onMyLocationClick方法里的Toast字符串写了硬换行,会直接编译报错,记得改成转义换行符:"Current location:\n" + location。

内容的提问来源于stack exchange,提问作者mabdelouahad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:24:18