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

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管理标记位置,同样无效。

原因分析
  1. 相机视角未覆盖标记位置:标记可能已添加,但地图相机停留在初始位置,导致看不到新标记。
  2. Firestore查询逻辑缺陷:嵌套查询中每次子查询完成就调用addShopsLatnLong,此时ShopsList可能还未收集全所有商家ID,导致部分标记未添加。
  3. 全局变量初始化时机问题:constants变量在onMapReady中才初始化,若addShopsLatnLong先于onMapReady执行,会导致constants.getOwner()为空,查询失败。
  4. 极端场景下的线程问题:虽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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:22:38