Android Studio中OnMapReady方法内无法获取getter返回值的问题
问题原因
你遇到的空指针崩溃由以下几个问题共同导致:
sosrecords实例未初始化:你只声明了全局变量SosRecords sosrecords;,没有创建实例就直接调用setCallFor()、setLatitude()等方法,不仅会直接触发空指针,就算没触发,实例内部的Latitude、Longitude默认值也是null- 时序逻辑错误:你在点击Proceed按钮后,先执行Firestore异步查询,之后才启动定位更新。定位回调
onLocationResult是异步触发的,你在Firestore成功回调里取经纬度时,大概率还没收到定位结果,Latitude和Longitude还是null - 包装类默认空值问题:
SosRecords类中经纬度用的是包装类Double,没有设置初始值的情况下默认值为null,LatLng构造方法需要传入基本类型double,自动拆箱时遇到null就会抛出你收到的空指针报错
解决方案
步骤1:初始化SosRecords实例
在Activity的onCreate生命周期方法中初始化实例,并给经纬度设置默认值:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 你的原有布局加载等逻辑 setContentView(R.layout.activity_main); // 新增初始化逻辑 sosrecords = new SosRecords(); // 设置默认经纬度,避免未获取定位时空值问题 sosrecords.setLatitude(0.0); sosrecords.setLongitude(0.0); // 其他原有初始化逻辑 }
步骤2:调整时序+增加空值判断
把启动定位的逻辑放到Firestore查询之前,同时所有取经纬度的地方都增加空值判断,避免拆箱空指针:
首先修改按钮点击逻辑,先启动定位:
builder.setPositiveButton("Proceed", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 先判断定位权限,启动定位 if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)== PackageManager.PERMISSION_GRANTED){ checkSettingsAndStartLocationUpdates(); }else{ askLocationPermission(); dialog.dismiss(); return; } sosrecords.setCallFor(selectedOfficer); startclicked= false; // 不要手动调用onStart,这是系统生命周期方法,系统会自动触发 // 原有Firestore查询逻辑保留 if(FirebaseAuth.getInstance().getCurrentUser()!= null){ DocumentReference df = FirebaseFirestore.getInstance().collection("Users").document(FirebaseAuth.getInstance().getCurrentUser().getUid()); df.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() { @Override public void onSuccess(DocumentSnapshot documentSnapshot) { if(documentSnapshot.getString("FullName")!= null){ String id = reff.push().getKey(); Log.d(TAG, "asdasd"+id); // 取经纬度前先做空判断 Double lat = sosrecords.getLatitude(); Double lon = sosrecords.getLongitude(); if(lat == null || lon == null){ Toast.makeText(MainActivity.this, "暂未获取到位置,请稍后重试", Toast.LENGTH_SHORT).show(); return; } SosRecords sosRecords = new SosRecords(documentSnapshot.getString("FullName"), documentSnapshot.getString("PhoneNumber"), documentSnapshot.getString("UserEmail"), lat, lon, sosrecords.getCallFor()); reff.child(id).setValue(sosRecords); sosrecords.setRecordID(id); btnStartSOS.setEnabled(false); btnStopSOS.setEnabled(true); Toast.makeText(MainActivity.this, "你已成功触发SOS请求!", Toast.LENGTH_SHORT).show(); LatLonLoop.run(); smf.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { // 这里同样做空判断 Double mapLat = sosrecords.getLatitude(); Double mapLon = sosrecords.getLongitude(); if(mapLat == null || mapLon == null){ Toast.makeText(MainActivity.this, "暂未获取到位置,无法标记", Toast.LENGTH_SHORT).show(); return; } LatLng latLng = new LatLng(mapLat, mapLon); MarkerOptions markerOptions = new MarkerOptions().position(latLng).title("当前位置"); googleMap.addMarker(markerOptions); googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,15)); } }); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { FirebaseAuth.getInstance().signOut(); startActivity(new Intent(getApplicationContext(),Login.class)); finish(); } }); } dialog.dismiss(); } });
步骤3:实现实时更新位置标记(可选)
如果需要定位更新后自动刷新地图标记,可新增全局变量存储GoogleMap和Marker实例,在定位回调中更新标记:
首先新增全局变量:
private GoogleMap mMap; private Marker currentMarker;
修改onMapReady逻辑:
@Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; Double mapLat = sosrecords.getLatitude(); Double mapLon = sosrecords.getLongitude(); if(mapLat != null && mapLon != null){ LatLng latLng = new LatLng(mapLat, mapLon); currentMarker = mMap.addMarker(new MarkerOptions().position(latLng).title("当前位置")); mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,15)); } }
修改定位回调onLocationResult逻辑:
@Override public void onLocationResult(LocationResult locationResult) { if (locationResult == null) { return; } for (Location location : locationResult.getLocations()) { double lat = location.getLatitude(); double lon = location.getLongitude(); sosrecords.setLatitude(lat); sosrecords.setLongitude(lon); // 实时更新地图标记 if(mMap != null){ LatLng newLatLng = new LatLng(lat, lon); if(currentMarker == null){ currentMarker = mMap.addMarker(new MarkerOptions().position(newLatLng).title("当前位置")); }else{ currentMarker.setPosition(newLatLng); } mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newLatLng,15)); } } }
内容的提问来源于stack exchange,提问作者WEI ZHUANG GOH
相关产品推荐
相关产品推荐

