`对象常量{
fun buildWelcomeMessage(): String {
return StringBuilder("Welcome, ")
.append(currentRider!!.firstName)
.append(" ")
.append(currentRider!!.lastName)
.toString()
}
fun buildName(firstName: String, lastName: String): String {
return StringBuilder(firstName).append("").append(lastName).toString()
}
var marketList: MutableMap<String, Marker> = HashMap()
var driversFound: MutableSet<DriverGeoModel> = HashSet()
const val DRIVER_INFO_REFERENCE = "DriverInfo"
const val RIDER_INFO_REFERENCE: String = "Riders"
const val CHANNEL_ID = "myChannelRider"
const val DRIVERS_LOCATION_REFERENCES: String = "DriversLocation"
var currentRider: RiderModel? = null
const val TOKEN_REFERENCE: String = "Token"`
class HomeFragment : Fragment(), OnMapReadyCallback, FirebaseDriverInfoListener {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private lateinit var mMap: GoogleMap
private var _mapFragment: SupportMapFragment? = null
//location
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
//Load driver
private var distance = 1.0
private val LIMIT_RANGE = 10.0
private var previousLocation: Location? = null
private var currentLocation: Location? = null
private var firstTime = true
private var cityName = ""
//listener
lateinit var iFirebaseDriverLocationListener: FirebaseDriverInfoListener
lateinit var iFirebaseFailedListener: FirebaseFailedListener
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
_mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
_mapFragment!!.getMapAsync(this)
init()
return root
}
override fun onDestroyView() {
super.onDestroyView()
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
_binding = null
}
private fun init() {
iFirebaseDriverLocationListener = this
locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 3000).apply {
setWaitForAccurateLocation(false)
setMinUpdateIntervalMillis(LocationRequest.Builder.IMPLICIT_MIN_UPDATE_INTERVAL)
setMaxUpdateDelayMillis(5000)
setMinUpdateDistanceMeters(10f)
}.build()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
//set the location on map
val newPos = LatLng(
locationResult.lastLocation!!.latitude, locationResult.lastLocation!!.longitude
)
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newPos, 18f))
//if user has change location, calculate and load driver again
if (firstTime) {
previousLocation = locationResult.lastLocation
currentLocation = locationResult.lastLocation
firstTime = false
} else {
previousLocation = currentLocation
currentLocation = locationResult.lastLocation
}
if (previousLocation!!.distanceTo(currentLocation!!) / 1000 <= LIMIT_RANGE) {
loadAvailableDrivers()
}
}
}
fusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(requireContext())
if (ContextCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.myLooper()
)
} else {
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 12
)
}
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.myLooper()
)
loadAvailableDrivers()
}
private fun loadAvailableDrivers() {
if (ActivityCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
Snackbar.make(
requireView(), getString(R.string.permission_required), Snackbar.LENGTH_SHORT
).show()
return
}
fusedLocationProviderClient.lastLocation.addOnFailureListener { e ->
Snackbar.make(requireView(), e.message!!, Snackbar.LENGTH_SHORT).show()
}.addOnSuccessListener { location ->
if (location != null) {
// Load all drivers in the city based on the obtained location
val geoCoder = Geocoder(requireContext(), Locale.getDefault())
val addressList: List<Address>?
try {
@Suppress("DEPRECATION")
addressList =
geoCoder.getFromLocation(location.latitude, location.longitude, 1)
val cityName = addressList!![0].locality
//Query
val driverLocationRef = FirebaseDatabase.getInstance()
.getReference(Constants.DRIVERS_LOCATION_REFERENCES).child(cityName)
val gf = GeoFire(driverLocationRef)
val geoQuery = gf.queryAtLocation(
GeoLocation(location.latitude, location.longitude), distance
)
geoQuery.removeAllListeners()
geoQuery.addGeoQueryEventListener(object : GeoQueryEventListener {
override fun onKeyEntered(key: String?, location: GeoLocation?) {
Constants.driversFound.add(DriverGeoModel(key, location))
}
override fun onKeyExited(key: String?) {
Constants.driversFound.remove(DriverGeoModel(key))
}
override fun onKeyMoved(key: String?, location: GeoLocation?) {
}
override fun onGeoQueryReady() {
if (distance <= LIMIT_RANGE) {
distance++
loadAvailableDrivers()
} else {
distance = 0.0
addDriverMarker()
}
}
override fun onGeoQueryError(error: DatabaseError?) {
Snackbar.make(
requireView(), error!!.message, Snackbar.LENGTH_SHORT
).show()
}
})
driverLocationRef.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(
snapshot: DataSnapshot,
previousChildName: String?,
) {
//Have new Driver
val geoQueryModel = snapshot.getValue(GeoQueryModel::class.java)
val geoLocation =
GeoLocation(geoQueryModel!!.l!![0], geoQueryModel.l!![1])
val driverGeoModel = DriverGeoModel(snapshot.key, geoLocation)
val newDriverLocation = Location("")
newDriverLocation.latitude = geoLocation.latitude
newDriverLocation.longitude = geoLocation.longitude
val newDistance = location.distanceTo(newDriverLocation) / 1000 //in km
if (newDistance <= LIMIT_RANGE) {
findDriverByKey(driverGeoModel)
}
}
override fun onChildChanged(
snapshot: DataSnapshot,
previousChildName: String?,
) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
val removedDriverKey = snapshot.key
Constants.driversFound.removeAll { it.key == removedDriverKey }
// Remove the marker from the map
if (Constants.marketList.containsKey(removedDriverKey)) {
Constants.marketList[removedDriverKey]?.remove()
Constants.marketList.remove(removedDriverKey)
}
}
override fun onChildMoved(
snapshot: DataSnapshot,
previousChildName: String?,
) {
}
override fun onCancelled(error: DatabaseError) {
Snackbar.make(
requireView(), error.message, Snackbar.LENGTH_SHORT
).show()
}
})
} catch (e: IOException) {
Snackbar.make(
requireView(),
getString(R.string.permission_required),
Snackbar.LENGTH_SHORT
).show()
}
} else {
Snackbar.make(
requireView(), "Unable to retrieve location information.", Snackbar.LENGTH_SHORT
).show()
}
}
}
private fun addDriverMarker() {
Log.d("MarkerDebug", "addDriverMarker is called ")
if (Constants.driversFound.isNotEmpty()) {
CoroutineScope(Dispatchers.IO).launch {
val newDriverKeys = Constants.driversFound.map { it.key }
val existingDriverKeys = Constants.marketList.keys
// Remove markers for drivers that are no longer in the list
val removedDriverKeys = existingDriverKeys.subtract(newDriverKeys.toSet())
for (key in removedDriverKeys) {
Constants.marketList[key]?.remove()
Constants.marketList.remove(key)
}
// Add or update markers for new or existing drivers
Constants.driversFound.forEach { driverGeoModel ->
findDriverByKey(driverGeoModel)
Log.d("MarkerDebug", "addDriverMarker is called when found driver: ${driverGeoModel.key}")
}
}
Snackbar.make(
requireView(), getString(R.string.drivers_are_found), Snackbar.LENGTH_SHORT
).show()
} else {
// No drivers found, remove all markers from the map
for (marker in Constants.marketList.values) {
marker.remove()
}
Constants.marketList.clear()
Snackbar.make(
requireView(), getString(R.string.drivers_are_not_found), Snackbar.LENGTH_SHORT
).show()
}
}
private fun findDriverByKey(driverGeoModel: DriverGeoModel?) {
FirebaseDatabase.getInstance().getReference(Constants.DRIVER_INFO_REFERENCE)
.child(driverGeoModel!!.key!!)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
iFirebaseFailedListener.onFirebaseFailed(error.message)
}
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.hasChildren()) {
driverGeoModel.driverInfoModel =
(snapshot.getValue(DriverInfoModel::class.java))
iFirebaseDriverLocationListener.onDriverInfoLoadSuccess(driverGeoModel)
} else {
iFirebaseFailedListener.onFirebaseFailed(getString(R.string.key_not_found) + driverGeoModel.key)
}
}
})
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
//enable zoom
mMap.uiSettings.isZoomControlsEnabled = true
//check the permission
if (ActivityCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
//if we don't have permission
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 12
)
return
}
//when we have permission
if (ContextCompat.checkSelfPermission(
requireContext(), Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) { //Enable button first
mMap.isMyLocationEnabled = true
mMap.uiSettings.isMyLocationButtonEnabled = true
//when i click on button
mMap.setOnMyLocationButtonClickListener {
Toast.makeText(context, "clicked", Toast.LENGTH_LONG).show()
//get last location
fusedLocationProviderClient.lastLocation.addOnFailureListener {
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
}.addOnSuccessListener { location ->
val userLatLng = LatLng(location.latitude, location.longitude)
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(userLatLng, 18f))
}
true
}
val locationButton = (_mapFragment!!.requireView()
.findViewById<View>("1".toInt()).parent!! as View).findViewById<View>("2".toInt())
val params = locationButton.layoutParams as RelativeLayout.LayoutParams
params.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0)
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE)
params.addRule(RelativeLayout.ALIGN_PARENT_START, 0)
params.marginStart = 15
params.bottomMargin = 250
}
//try to set map style
try {
val success = mMap.setMapStyle(
MapStyleOptions.loadRawResourceStyle(requireContext(), R.raw.uber_maps_style)
)
if (!success) {
Log.e("ErrorMap", "Map Style is not parsing")
}
} catch (e: Exception) {
Log.e("ErrorMap", e.message!!)
}
addDriverMarker()
}
override fun onDriverInfoLoadSuccess(driverGeoModel: DriverGeoModel?) {
val driverKey = driverGeoModel?.key
if (driverKey != null) {
if (!Constants.marketList.containsKey(driverKey)) {
val marker = mMap.addMarker(
MarkerOptions().position(
LatLng(
driverGeoModel.geoLocation!!.latitude,
driverGeoModel.geoLocation!!.longitude
)
).flat(true).title(
Constants.buildName(
driverGeoModel.driverInfoModel?.firstName ?: "",
driverGeoModel.driverInfoModel?.lastName ?: ""
)
).snippet(driverGeoModel.driverInfoModel?.phoneNumber ?: "")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.car))
)
Log.d("MarkerDebug", "Adding marker for driver: ${driverGeoModel.key}")
Constants.marketList[driverKey] = marker!!
}
}
if (!TextUtils.isEmpty(cityName)) {
val driverLocation =
FirebaseDatabase.getInstance().getReference(Constants.DRIVERS_LOCATION_REFERENCES)
.child(cityName).child(driverKey ?: "")
driverLocation.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Snackbar.make(
requireView(), error.message, Snackbar.LENGTH_SHORT
).show()
}
override fun onDataChange(snapshot: DataSnapshot) {
if (!snapshot.hasChildren() && Constants.marketList.containsKey(driverKey)) {
// Remove the marker from the map
Constants.marketList[driverKey]?.remove()
Constants.marketList.remove(driverKey)
driverLocation.removeEventListener(this)
}
}
})
}
}
override fun onDestroy() {
super.onDestroy()
_mapFragment = null
}
}
这个是骑手应用程序,当骑手打开并等待在线司机时,在司机应用程序中,当司机在线时,它应该在谷歌地图中显示在线司机标记,当应用程序第一次启动时(安装后)并且它按预期工作并显示在地图上,如果驾驶员离线则删除。 当应用程序第二次启动时(安装后)小吃起作用,说找到了驱动程序,并且除了标记之外的所有东西都没有显示在地图上
到目前为止我已经修复了 `私人乐趣刷新Map(){ // 删除地图上的所有标记 for (Constants.marketList.values 中的标记) { 标记.remove() } Constants.marketList.clear() // 根据需要重置任何其他与标记相关的对象或数据 Constants.driversFound.clear() distance = 1.0 // 重置查询司机的距离 firstTime = true // 重置firstTime标志 // 再次加载可用的驱动程序 加载可用驱动程序() }
override fun onDestroy() {
super.onDestroy()
_mapFragment = null
refreshMap()
}`