在同一张地图上显示多个注册用户的位置(Android Studio、Firebase、Kotlin)

Posted

技术标签:

【中文标题】在同一张地图上显示多个注册用户的位置(Android Studio、Firebase、Kotlin)【英文标题】:Show multiple registered user`s location on the same map (Android Studio, Firebase, Kotlin) 【发布时间】:2021-07-26 01:52:06 【问题描述】:

所以我的应用会在地图上显示我的位置,并将纬度/经度保存到 Firebase。看起来是这样的:

我的用户位置的当前路径只是“/users/userlocation”。 但是,我想在每个用户下保存“用户位置”,然后我希望所有这些标记都显示在我已经在这里创建的同一张地图上:

地图活动:



    private lateinit var map: GoogleMap
    private val LOCATION_PERMISSION_REQUEST = 1
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest
    private lateinit var locationCallback: LocationCallback


    private fun getLocationAccess() 
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) 
            map.isMyLocationEnabled = true
            getLocationUpdates()
            startLocationUpdates()
        
        else
            ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST)
    

    private fun getLocationUpdates() 
            locationRequest = LocationRequest()
            locationRequest.interval = 30000
            locationRequest.fastestInterval = 20000
            locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY

            locationCallback = object : LocationCallback() 
                override fun onLocationResult(locationResult: LocationResult) 
                    if (locationResult.locations.isNotEmpty()) 
                        val location = locationResult.lastLocation

                        lateinit var databaseRef: DatabaseReference
                        databaseRef = Firebase.database.reference
                        val locationlogging = LocationLogging(location.latitude, location.longitude)
                        databaseRef.child("/users/userlocation").setValue(locationlogging)

                                .addOnSuccessListener 
                                    Toast.makeText(applicationContext, "Locations written into the database", Toast.LENGTH_LONG).show()
                                
                                .addOnFailureListener 
                                    Toast.makeText(applicationContext, "Error occured while writing the locations", Toast.LENGTH_LONG).show()
                                


                        if (location != null) 
                            val latLng = LatLng(location.latitude, location.longitude)
                            val markerOptions = MarkerOptions().position(latLng)
                            map.addMarker(markerOptions)
                            map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
                        
                    
                
            
        

    @SuppressLint("MissingPermission")
    private fun startLocationUpdates() 
        fusedLocationClient.requestLocationUpdates(locationRequest,locationCallback, null)
    


    @SuppressLint("MissingPermission")
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) 
        if (requestCode == LOCATION_PERMISSION_REQUEST) 
            if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) 
                map.isMyLocationEnabled = true
             else  Toast.makeText(this, "User has not granted location access permission", Toast.LENGTH_LONG).show()
                finish()
            
        
    

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    


    override fun onMapReady(googleMap: GoogleMap) 
        map = googleMap
        getLocationAccess()
    

这是我尝试过的:

@Parcelize
class User(val uid: String, val username: String, val profileImageUrl: String, locationlogging: String): Parcelable 
  constructor() : this("", "", "", "")
 

我在我的 User.kt 文件中添加了“locationlogging”作为字符串,但我在这里可能完全错了。

我尝试在我的 saveUserToFirebaseDatabase 函数中将此添加到我的 RegisterActivity:

 // Save user to firebase database
 private fun saveUserToFirebaseDatabase(profileImageUrl: String) 
        val uid = FirebaseAuth.getInstance().uid ?: ""
        val ref = FirebaseDatabase.getInstance().getReference("/users/$uid")
        val user = User(uid, username_edittext_register.text.toString(), profileImageUrl)

我不是 100% 确定,但我认为这是我应该实现用户位置的部分,因此应该将其添加到所有注册成员中,就像个人资料图片 URL、uid 和用户名一样。我尝试的任何事情都会给我错误。我完全偏离轨道了吗? 如何将每个注册用户的位置添加到我的 Firebase 中,以便在 Google 地图上同时显示所有用户?

【问题讨论】:

您必须将数据非规范化到另一个节点,在那里您可以获得引脚/配置文件以及位置所需的浅层信息 【参考方案1】:

您当前的位置路径是:

/users/userlocation

这似乎不正确,因为每个用户对象都应该有自己的位置。为此,您可以采用以下三种方法之一:

Firebase-root
  |
  --- users
       |
       --- $uid
            |
            --- profileImageUrl: "https://..."
            |
            --- uid: "h9xZs...bV82"
            |
            --- username: "Bad Pug"
            |
            --- location
                  |
                  --- latitude: 53.37...
                  |
                  --- longitude: -0.90...

意思是“位置”是包含纬度和经度的地图。第二种方法可能是直接在 User 对象下添加纬度和经度:

Firebase-root
  |
  --- users
       |
       --- $uid
            |
            --- profileImageUrl: "https://..."
            |
            --- uid: "h9xZs...bV82"
            |
            --- username: "Bad Pug"
            |
            --- latitude: 53.37...
            |
            --- longitude: -0.90...

如果您考虑在某个时间点尝试使用Cloud Firestore,您可以使用地理点,因为它是supported data type。您的 Firestore 架构可能如下所示:

Firestore-root
  |
  --- users (collection)
       |
       --- $uid (document)
            |
            --- profileImageUrl: "https://..."
            |
            --- uid: "h9xZs...bV82"
            |
            --- username: "Bad Pug"
            |
            --- geoPoint: [53.37...° N,  -0.90...° E]

解决这个问题的关键是添加一个 Map(对于第一个解决方案)、两个新的双属性(对于第二个解决方案)或一个 GeoPoint 对象(对于第三个解决方案),并填充相应的纬度和经度值。将 User 对象写入数据库后,您将拥有上述架构之一。

编辑:

在代码中,要获取第二个示例中的纬度和经度,请使用以下代码行:

val uid = FirebaseAuth.getInstance().currentUser?.uid
val rootRef =  FirebaseFirestore.getInstance()
val usersRef = rootRef.collection("users")
val uidRef = usersRef.document(uid)
uidRef.get()
    .addOnSuccessListener  document ->
        if (document != null) 
            val latitude = document.getDouble("latitude")
            val longitude = document.getDouble("longitude")
            Log.d(TAG, latitude + ", " + longitude)
         else 
            Log.d(TAG, "No such document")
        
    
    .addOnFailureListener  exception ->
        Log.d(TAG, "get failed with ", exception)
    

logcat 中的结果将是:

53.37..., -0.90...

【讨论】:

感谢您的解释,现在变得更容易理解了。在我的地图活动中,这种编码在实践中会是什么样子?另外,如果我实现了您提到的任何这些想法(假设是最合乎逻辑和更容易的)并且每个用户都将拥有坐标,那么它会自动作为标记出现在地图活动中吗? 它看起来像我更新的答案。获得纬度和经度后,您可以在 Google 地图上添加标记。不会自动添加,请write some code for that。 感谢您的帮助。我按照您的说明进行操作,不同的设备坐标开始出现在我的 Logcat 中,但我的 Firebase 实时数据库中没有任何变化。我做错了什么?有什么建议吗? 现在发生的事情是,我所有的用户详细信息都被/users下的经纬度替换了。 如果坐标显示在 logcat 中,这是个好消息,代码有效。没有看到代码,很难说哪里出了问题。很可能您使用的是 set() 而不是 update()。

以上是关于在同一张地图上显示多个注册用户的位置(Android Studio、Firebase、Kotlin)的主要内容,如果未能解决你的问题,请参考以下文章

Google Maps JavaScript API 在同一张地图上显示两条不同折线样式的路线

如何在注册时使用 google maps api 在全球地图中显示自动注册用户的地理位置?

如何在同一张地图上使用带有多个标记的谷歌地图 API

在地图上同时显示多个用户的位置(Kotlin、Firebase 实时数据库)

Swift GeoPoint 获取所有用户位置 ios

快速显示用户位置