Firebase异步获取位置后Google Map无法显示新标记问题
问题:Google Map异步添加标记不显示
我的Fragment集成了Google Map和SearchView,用户从建议列表选择商品后,需要从Firebase异步获取商家位置并在地图上添加标记。已经在onMapReady中将googleMap赋值给全局变量map,但调用map.addMarker()时标记不显示,App也没有崩溃。
相关代码片段
添加标记的函数
private void addShopsLatnLong(List<String> shopsList) { newPoints = true; if (shopsList.size() > 0) { Log.d(TAG, "addshops called"); FirebaseFirestore firestore = FirebaseFirestore.getInstance(); for (String shopId : shopsList) { firestore.collection(constants.getOwner()).document(shopId) .get() .addOnSuccessListener(documentSnapshot -> { Profile profile = documentSnapshot.toObject(Profile.class); map.addMarker(new MarkerOptions().position(new LatLng(profile.getLatitude(),profile.getLongitude()))); Log.d(TAG, "points " + profile.getLatitude() + " " + profile.getLongitude()); }) .addOnFailureListener(e -> Log.d(TAG, "error: " + e.getMessage())); } } }
Map初始化代码
@Override public void onMapReady(@NonNull GoogleMap googleMap) { map = googleMap; Log.d(TAG, "onMapReady called"); runnable= () -> { for (LatLng latLng : locationArrayList) { map.addMarker(new MarkerOptions().position(latLng).title("new!!")); map.moveCamera(CameraUpdateFactory.newLatLng(latLng)); } }; if (newPoints) { Log.d(TAG, "size for new points - " + locationArrayList.size()); for (LatLng latLng : locationArrayList) { map.addMarker(new MarkerOptions().position(latLng).title("new!!")); map.moveCamera(CameraUpdateFactory.newLatLng(latLng)); } } else { firebaseAuth = FirebaseAuth.getInstance(); firebaseFirestore = FirebaseFirestore.getInstance(); constants = new FiresStoreTableConstants(); final String email = firebaseAuth.getCurrentUser().getEmail(); firebaseFirestore.collection(constants.getCustomer()).document(email) .get() .addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() { @Override public void onSuccess(DocumentSnapshot documentSnapshot) { Profile profile = documentSnapshot.toObject(Profile.class); Log.d(TAG, "profile:" + profile); LatLng you = new LatLng(profile.getLatitude(), profile.getLongitude()); map.addMarker(new MarkerOptions().position(you).title("You!!")); map.moveCamera(CameraUpdateFactory.newLatLng(you)); } }) .addOnFailureListener(e -> e.printStackTrace()); } }
已尝试的解决方法:
- 在
onMapReady中创建添加标记的Runnable,未生效; - 使用LiveData管理标记位置,同样无效。
原因分析
- 相机视角未覆盖标记位置:标记可能已添加,但地图相机停留在初始位置,导致看不到新标记。
- Firestore查询逻辑缺陷:嵌套查询中每次子查询完成就调用
addShopsLatnLong,此时ShopsList可能还未收集全所有商家ID,导致部分标记未添加。 - 全局变量初始化时机问题:
constants变量在onMapReady中才初始化,若addShopsLatnLong先于onMapReady执行,会导致constants.getOwner()为空,查询失败。 - 极端场景下的线程问题:虽Firebase回调默认在主线程,但极端情况可能在后台线程操作Map,导致标记无法渲染。
解决方案
1. 确保主线程操作Google Map
在Firebase回调中,通过Handler将添加标记的操作切换到主线程(保险起见):
private void addShopsLatnLong(List<String> shopsList) { newPoints = true; if (shopsList.size() > 0) { Log.d(TAG, "addshops called"); FirebaseFirestore firestore = FirebaseFirestore.getInstance(); Handler mainHandler = new Handler(Looper.getMainLooper()); for (String shopId : shopsList) { firestore.collection(constants.getOwner()).document(shopId) .get() .addOnSuccessListener(documentSnapshot -> { Profile profile = documentSnapshot.toObject(Profile.class); if (profile != null && map != null) { LatLng shopLatLng = new LatLng(profile.getLatitude(), profile.getLongitude()); mainHandler.post(() -> { map.addMarker(new MarkerOptions().position(shopLatLng).title("商家")); // 可选:调整相机到新标记位置 map.moveCamera(CameraUpdateFactory.newLatLngZoom(shopLatLng, 12)); }); Log.d(TAG, "points " + profile.getLatitude() + " " + profile.getLongitude()); } }) .addOnFailureListener(e -> Log.d(TAG, "error: " + e.getMessage())); } } }
2. 修复Firestore查询逻辑,等待所有子查询完成
当前嵌套查询会多次调用addShopsLatnLong,导致重复操作且数据不完整。改用Tasks.whenAll等待所有子查询完成后再处理:
// 在onQueryTextSubmit的成功回调中修改: @Override public void onSuccess(QuerySnapshot queryDocumentSnapshots) { List<DocumentSnapshot> ids = queryDocumentSnapshots.getDocuments(); Log.d(TAG, "OWNER IDS " + ids.size()); List<Task<?>> tasks = new ArrayList<>(); ShopsList = new ArrayList<>(); for (DocumentSnapshot id : ids) { Task<QuerySnapshot> task = fStore.collection(constants.getOwner()).document(id.getId()).collection(constants.getOwnerAvailability()) .whereGreaterThan(constants.getOwnerQuantity(), 0) .get() .addOnSuccessListener(querySnapshot -> { for (DocumentSnapshot doc : querySnapshot.getDocuments()) { if (doc.getId().equals(barcode)) { ShopsList.add(id.getId()); } } }) .addOnFailureListener(e -> Log.d(TAG, "Error: " + e.getMessage())); tasks.add(task); } // 等待所有子查询完成后再添加标记 Tasks.whenAll(tasks).addOnCompleteListener(task -> { if (task.isSuccessful()) { addShopsLatnLong(ShopsList); Log.d(TAG, "最终商家列表:" + ShopsList); } }); }
3. 提前初始化全局变量constants
在onCreateView中初始化constants,避免空指针:
@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentSearchViewBinding.bind(inflater.inflate(R.layout.fragment_search_view, container, false)); // 提前初始化constants constants = new FiresStoreTableConstants(); // ... 其他代码 }
4. 批量调整相机视角,显示所有标记
如果需要一次性显示所有商家标记,可以计算所有位置的边界,然后调整相机:
// 新增方法:调整相机到包含所有标记的区域 private void fitCameraToMarkers(List<LatLng> latLngList) { if (latLngList.isEmpty() || map == null) return; LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (LatLng latLng : latLngList) { builder.include(latLng); } LatLngBounds bounds = builder.build(); int padding = 100; // 边距,单位px CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, padding); map.animateCamera(cameraUpdate); }
修改addShopsLatnLong来收集位置并调用该方法:
private void addShopsLatnLong(List<String> shopsList) { newPoints = true; if (shopsList.size() > 0) { Log.d(TAG, "addshops called"); FirebaseFirestore firestore = FirebaseFirestore.getInstance(); Handler mainHandler = new Handler(Looper.getMainLooper()); List<LatLng> shopLocations = new ArrayList<>(); for (String shopId : shopsList) { firestore.collection(constants.getOwner()).document(shopId) .get() .addOnSuccessListener(documentSnapshot -> { Profile profile = documentSnapshot.toObject(Profile.class); if (profile != null && map != null) { LatLng shopLatLng = new LatLng(profile.getLatitude(), profile.getLongitude()); shopLocations.add(shopLatLng); mainHandler.post(() -> { map.addMarker(new MarkerOptions().position(shopLatLng).title("商家")); }); Log.d(TAG, "points " + profile.getLatitude() + " " + profile.getLongitude()); } }) .addOnFailureListener(e -> Log.d(TAG, "error: " + e.getMessage())) .addOnCompleteListener(task -> { // 所有查询完成后调整相机 if (shopLocations.size() == shopsList.size()) { mainHandler.post(() -> fitCameraToMarkers(shopLocations)); } }); } } }
内容的提问来源于stack exchange,提问作者Yuga Ganesh Vasaikar
相关产品推荐
相关产品推荐

