求助:我的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) {} };
额外要注意的点
- 布局文件必须包含
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"/>
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
相关产品推荐
相关产品推荐

