Google Map自定义Marker仅显示一个的技术求助
解决Google Map自定义Marker仅显示一个的问题
我仔细看了你的代码,发现问题主要出在全局复用同一个View生成Marker图标上,还有一些循环逻辑可以优化,下面给你一步步拆解和修复:
问题根源
- 全局View导致Bitmap复用冲突:你定义了全局的
View child,只在初始化时inflate了一次布局。每次调用getMarkerImage时,都是修改同一个View的文本然后生成Bitmap——这会导致所有Marker的Icon最终都指向最后一次生成的Bitmap对象,前面的Marker图标会被后续的绘制覆盖,自然就只能看到最后一个Marker的自定义图标了。 - 嵌套循环逻辑冗余:在
onDataChange里,你先遍历用户快照,再嵌套遍历UIDLocation的所有条目,不仅效率低,还可能导致同一个Marker被重复修改,出现不必要的逻辑混乱。
修复方案
1. 每次生成图标时创建独立的View实例
把View child的初始化移到getMarkerImage方法内部,每次调用都inflate一个全新的View,这样每个Marker的图标都是基于独立的View生成,不会互相干扰。
2. 优化循环逻辑,减少不必要的遍历
先把符合条件的用户key和数据存到集合里,再直接遍历已有的Marker集合,根据key判断是否需要显示并设置图标,这样比嵌套循环高效得多。
修改后的完整代码
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() { @Override public void onKeyEntered(String key, GeoLocation location) { UIDLocation.put(key,location); Marker marker = mMap.addMarker(new MarkerOptions() .position(new LatLng(location.latitude, location.longitude)) .title(key)); markers.put(key, marker); } }); // MarkeringMap is called when someone click on card which contains the category names public void MarkeringMap(String string){ Query query = FirebaseDatabase.getInstance().getReference().child("WorkMen") .orderByChild("subcategory") .startAt(string) .endAt(string + "\uf8ff") .limitToLast(50); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if(dataSnapshot.exists()) { Toast.makeText(getActivity(),"there is something",Toast.LENGTH_SHORT).show(); } // 先把符合条件的用户key和数据存到集合中 Set<String> validUserKeys = new HashSet<>(); Map<String, Users> validUsersMap = new HashMap<>(); usersLists.clear(); // 清空旧数据避免重复 for (DataSnapshot usersnapshot : dataSnapshot.getChildren()) { Users users = usersnapshot.getValue(Users.class); usersLists.add(users); Toast.makeText(getActivity(),users.getName()+"this is username ",Toast.LENGTH_SHORT).show(); String keystring = usersnapshot.getKey(); validUserKeys.add(keystring); validUsersMap.put(keystring, users); } // 遍历所有Marker,统一更新显示状态和图标 for (Map.Entry<String, Marker> entry : markers.entrySet()) { Marker marker = entry.getValue(); String key = entry.getKey(); if (validUserKeys.contains(key)) { // 显示符合条件的Marker并设置自定义图标 marker.setVisible(true); Users user = validUsersMap.get(key); Bitmap b = getMarkerImage(user.getName()); marker.setIcon(BitmapDescriptorFactory.fromBitmap(b)); } else { // 隐藏不符合条件的Marker marker.setVisible(false); } } } @Override public void onCancelled(DatabaseError databaseError) { // 处理查询取消的异常,方便调试 Log.e("FirebaseQuery", "Query cancelled", databaseError.toException()); } }); } public Bitmap getMarkerImage(String name){ // 每次调用都实例化新的View,彻底避免复用冲突 View child = getLayoutInflater().inflate(R.layout.category_tags_items, null); TextView textView1 = (TextView)child.findViewById(R.id.tag_Category_name); textView1.setText(name); // Drawable myDrawable = getResources().getDrawable(R.drawable.default_avatar); // 保留你的自定义Drawable设置 // 正确测量View并生成Bitmap child.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight()); child.buildDrawingCache(); Bitmap bitmap = Bitmap.createBitmap(child.getMeasuredWidth(), child.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN); Drawable drawable = child.getBackground(); if (drawable != null) { drawable.draw(canvas); } child.draw(canvas); // 销毁绘制缓存,避免内存泄漏 child.destroyDrawingCache(); return bitmap; }
额外优化建议
- 内存优化:如果需要生成大量自定义Marker图标,可以加入LruCache缓存机制,避免重复生成相同用户名的Bitmap,减少内存消耗。
- 调试优化:把调试用的Toast换成Log输出,频繁弹出Toast会影响用户体验。
- 性能优化:生成Bitmap的操作如果耗时较多,可以放到子线程中处理,避免阻塞主线程导致UI卡顿。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

