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数据库截图:
问题排查与修复方案
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
相关产品推荐
相关产品推荐

