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

Google Map标记无点击响应问题求助(Android+Firebase Firestore)

Android Google Maps + Firestore 标记点击对话框问题排查

我正在开发一款Android应用,使用Google Maps和Firebase Firestore数据库展示存储在Firestore中的静态地点列表。希望点击预定义位置的Marker时弹出对话框展示更多相关数据,但代码无法正常运行,请求协助排查问题。

以下是我的代码文件:

MapsActivity.java

import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;

import com.example.opshiva.databinding.ActivityMapsBinding;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QuerySnapshot;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener{

    private GoogleMap mMap;
    private static final int REQUEST_LOCATION_PERMISSION = 1;
    private ActivityMapsBinding binding;
    FirebaseFirestore firestoreDB;

    Location currentLocation;
    FusedLocationProviderClient fusedLocationProviderClient;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMapsBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        //instance of Firestore Database
        firestoreDB = FirebaseFirestore.getInstance();


        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(MapsActivity.this);

        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        getLastLocation();

    }
    private void getLastLocation() {

        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_LOCATION_PERMISSION);
            return;
        }
        Task<Location> task = fusedLocationProviderClient.getLastLocation();
        task.addOnSuccessListener(new OnSuccessListener<Location>() {
            @Override
            public void onSuccess(Location location) {
                if(location != null){
                    currentLocation = location;

                }
            }
        });
    }

    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setOnMarkerClickListener(this);
        addMarkersfromFirestore();

    }

    @Override
    public boolean onMarkerClick(@NonNull Marker marker) {

        Log.d("MarkerClick", "Marker clicked: " + marker.getTitle());
        String markerID = marker.getId();
        fetchDataFromFirestore(markerID);
        return true;
    }


    private void addMarkersfromFirestore() {

        firestoreDB.collection("MEDICAL")
                .get()
                .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                    @Override
                    public void onSuccess(QuerySnapshot queryDocumentSnapshots) {

                        for(DocumentSnapshot document : queryDocumentSnapshots ){
                            double latitude = document.getDouble("LATITUDE");
                            double longitude = document.getDouble("LONGITUDE");
                            LatLng location = new LatLng(latitude, longitude);
                            String title = document.getString("NAME");
                            Marker marker = mMap.addMarker(new MarkerOptions()
                                    .position(location)
                                    .title(title));
                            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location,10f));
                            Log.d("MarkerDetails", "Title: " + marker.getTitle() +
                                    ", Position: " + marker.getPosition());
                        }

                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d("Exception Occurred in markers", "" + e.getMessage());

                    }
                });

    }
    private void fetchDataFromFirestore(String markerID) {
        
        firestoreDB.collection("MEDICAL")
                .document(markerID)
                .get()
                .addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                    @Override
                    public void onSuccess(DocumentSnapshot documentSnapshot) {
                        
                        if(documentSnapshot.exists()){
                            showDataDialog(documentSnapshot);
                        }
                        
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d("Exception Occurred in reading data", "" + e.getMessage());
                    }
                });
        
    }

    private void showDataDialog(DocumentSnapshot documentSnapshot) {

        String oneField = documentSnapshot.getString("NAME");
        String twoField = documentSnapshot.getString("Phone");
        String threeField = documentSnapshot.getString("LATITUDE");
        String fourField = documentSnapshot.getString("LONGITUDE");

        MarkerDetailsDialogFragment dialogFragment = MarkerDetailsDialogFragment.newInstance(oneField,twoField,threeField,fourField);
        dialogFragment.show(getSupportFragmentManager(),"MarkerDetailsDialog");



    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == REQUEST_LOCATION_PERMISSION){
            if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED ){
                getLastLocation();
            }else{
                Toast.makeText(this, "Permission not granted", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

MarkerDetailsDialogFragment.java

public class MarkerDetailsDialogFragment extends DialogFragment {

    private static final String ARG_NAME = "NAME";
    private static final String ARG_Phone = "Phone";
    private static final String ARG_LATITUDE = "LATITUDE";
    private static final String ARG_LONGITUDE = "LONGITUDE";

    public static MarkerDetailsDialogFragment newInstance(String name, String phone, String latitude, String longitude){

        MarkerDetailsDialogFragment fragment = new MarkerDetailsDialogFragment();
        Bundle args = new Bundle();
        args.putString(ARG_NAME,name);
        args.putString(ARG_Phone,phone);
        args.putString(ARG_LATITUDE,latitude);
        args.putString(ARG_LONGITUDE,longitude);

        fragment.setArguments(args);
        return fragment;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity().getApplicationContext());
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.window_box, null);

        TextView oneTV = view.findViewById(R.id.textView_1);
        TextView twoTV = view.findViewById(R.id.textView_2);
        TextView threeTv =view.findViewById(R.id.textView_3);
        TextView fourTV = view.findViewById(R.id.textView_4);

        Bundle args = getArguments();
        if(args != null){
            oneTV.setText(args.getString(ARG_NAME));
            twoTV.setText(args.getString(ARG_Phone));
            threeTv.setText(args.getString(ARG_LATITUDE));
            fourTV.setText(args.getString(ARG_LONGITUDE));
        }
        builder.setView(view);


        return builder.create();
    }
}

Firestore数据库截图:
Firestore数据库截图


问题排查与修复方案

1. 核心问题:Marker ID与Firestore文档ID不匹配

你在onMarkerClick中使用marker.getId()获取的是Google Maps自动生成的标记ID(格式如m0、m1),并非Firestore中的文档ID(如hospital1),因此用这个ID查询Firestore会找不到对应文档,导致对话框无法加载数据。

修复代码:
添加Marker时,将Firestore文档ID存入Marker的tag:

// 在addMarkersfromFirestore的循环内修改
String docId = document.getId(); // 获取Firestore文档ID
Marker marker = mMap.addMarker(new MarkerOptions()
        .position(location)
        .title(title));
marker.setTag(docId); // 将文档ID存入标记的tag属性

点击Marker时从tag获取文档ID:

@Override
public boolean onMarkerClick(@NonNull Marker marker) {
    Log.d("MarkerClick", "Marker clicked: " + marker.getTitle());
    String docId = (String) marker.getTag(); // 从tag取出Firestore文档ID
    if (docId != null) {
        fetchDataFromFirestore(docId);
    }
    return true;
}

2. 数字类型字段获取错误

Firestore中的LATITUDE和LONGITUDE是double类型,用getString()会返回null,导致对话框中这两个字段显示为空。

修复代码:
在showDataDialog中正确获取数字类型字段并转为字符串:

private void showDataDialog(DocumentSnapshot documentSnapshot) {
    String oneField = documentSnapshot.getString("NAME");
    String twoField = documentSnapshot.getString("Phone");
    // 正确获取double类型并转为字符串
    Double latitude = documentSnapshot.getDouble("LATITUDE");
    Double longitude = documentSnapshot.getDouble("LONGITUDE");
    String threeField = latitude != null ? String.valueOf(latitude) : "";
    String fourField = longitude != null ? String.valueOf(longitude) : "";

    MarkerDetailsDialogFragment dialogFragment = MarkerDetailsDialogFragment.newInstance(oneField,twoField,threeField,fourField);
    dialogFragment.show(getSupportFragmentManager(),"MarkerDetailsDialog");
}

3. DialogFragment上下文错误

创建AlertDialog.Builder时使用getActivity().getApplicationContext()会导致上下文不匹配,可能引发异常。

修复代码:
改用getActivity()作为上下文:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

额外优化建议

  • 在addMarkersfromFirestore中,mMap.moveCamera放在循环内会导致地图最终定位到最后一个标记的位置,可改为循环结束后定位到当前位置(若已获取)或第一个标记的位置。
  • 在onMapReady中添加权限检查后启用地图的"我的位置"功能,提升用户体验:
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.setOnMarkerClickListener(this);
    // 权限检查通过后启用我的位置
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        mMap.setMyLocationEnabled(true);
    }
    addMarkersfromFirestore();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 20:10:55