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

求助:我的MapActivity为何导致Android应用崩溃?

兄弟,我帮你排查了代码和崩溃日志,问题很明确——空指针异常,根源是你在onCreate里过早操作了未初始化的对象,整个逻辑的执行顺序也错了。我给你拆解下问题,再一步步给出修复方案:

问题根源分析

从崩溃日志能看到,错误出在MapActivity.java:50,也就是你调用location.getLatitude()的时候,location是null。具体有这几个致命问题:

  • 地图初始化时机错误:mMap是在onMapReady异步回调里才会被赋值的,但你在onCreate里直接调用mMap.addMarker(),这时候mMap还没初始化(不过这次崩溃是location的锅,但这个也是潜在bug)。
  • 权限请求是异步的:你在getMyLocation里调用requestPermissions后,代码会直接往下执行,不会等用户点授权。这时候如果用户还没授权,locationManager.getLastKnownLocation()会返回null,甚至因为权限不足抛异常。
  • getLastKnownLocation本身可能返回null:如果设备从未获取过位置、位置服务关闭,这个方法就会返回null,你没做判断就直接用了。
  • getMyLocation里直接操作mMap:这时候mMap还没准备好,同样会触发空指针。

一步步修复方案

我们要把逻辑顺序调整过来:先等地图准备好→再检查权限→权限通过后再获取位置→最后操作地图

1. 修正onCreate方法

首先必须先设置布局(你原来的代码里居然没写setContentView!这也是大问题),然后触发地图的onMapReady回调:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 加载包含地图Fragment的布局
    setContentView(R.layout.activity_map);
    
    // 获取地图Fragment,触发onMapReady回调
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

2. 把核心逻辑移到onMapReady里

等地图准备好后,再去检查权限和获取位置:

@Override
public void onMapReady(GoogleMap googleMap) {
    Toast.makeText(this, "Map is Ready", Toast.LENGTH_SHORT).show();
    mMap = googleMap;
    
    // 先检查位置权限,再获取位置
    checkLocationPermissionAndGetLocation();
}

3. 完善权限请求和位置获取逻辑

拆分权限请求和位置获取的逻辑,处理权限回调:

private void checkLocationPermissionAndGetLocation() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
            != PackageManager.PERMISSION_GRANTED) {
        // 向用户请求位置权限
        ActivityCompat.requestPermissions(this, 
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 
                MY_PERMISSIONS_REQUEST_FINE_LOCATION);
    } else {
        // 权限已获取,直接获取位置并更新地图
        getMyLocationAndUpdateMap();
    }
}

// 处理权限请求的结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == MY_PERMISSIONS_REQUEST_FINE_LOCATION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 用户同意授权,获取位置
            getMyLocationAndUpdateMap();
        } else {
            Toast.makeText(this, "需要位置权限才能显示当前位置哦", Toast.LENGTH_SHORT).show();
        }
    }
}

private void getMyLocationAndUpdateMap() {
    LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    String bestProvider = locationManager.getBestProvider(criteria, false);
    
    if (bestProvider == null) {
        Toast.makeText(this, "找不到可用的位置服务", Toast.LENGTH_SHORT).show();
        return;
    }
    
    // 处理getLastKnownLocation可能返回null的情况
    Location location = locationManager.getLastKnownLocation(bestProvider);
    if (location != null) {
        // 添加当前位置标记
        mMap.addMarker(new MarkerOptions()
                .position(new LatLng(location.getLatitude(), location.getLongitude()))
                .title("My location"));
        
        // 移动相机到当前位置
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                new LatLng(location.getLatitude(), location.getLongitude()), 13));
        
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(new LatLng(location.getLatitude(), location.getLongitude()))
                .zoom(17)
                .bearing(90)
                .tilt(40)
                .build();
        mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
    } else {
        Toast.makeText(this, "无法获取历史位置,正在尝试获取实时位置...", Toast.LENGTH_SHORT).show();
        // 如果历史位置为空,请求实时位置更新
        locationManager.requestLocationUpdates(bestProvider, 1000, 0, locationListener);
    }
}

// 位置监听器,用于获取实时位置
private LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        if (location != null && mMap != null) {
            // 更新标记和相机位置
            mMap.clear();
            mMap.addMarker(new MarkerOptions()
                    .position(new LatLng(location.getLatitude(), location.getLongitude()))
                    .title("My location"));
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(location.getLatitude(), location.getLongitude()), 17));
            // 获取到位置后停止更新,避免耗电
            LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            locationManager.removeUpdates(this);
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}

    @Override
    public void onProviderEnabled(String provider) {}

    @Override
    public void onProviderDisabled(String provider) {}
};

额外要注意的点

  1. 布局文件必须包含SupportMapFragment:
    创建activity_map.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  1. AndroidManifest.xml要配置权限和API密钥:
<!-- 位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 声明需要GPS硬件 -->
<uses-feature android:name="android.hardware.location.gps" />

<!-- Google Maps API密钥,替换成你自己的 -->
<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="你的Google Maps API密钥"/>

这样调整后,就能彻底解决空指针问题,并且正确处理权限和位置获取的逻辑了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:27:34