在Androidstudio中实现获取用户的实时位置,并将它显示在 Google Map 上的 Marker 上。 计算用户位置和所有体检机构位置之间的距离,并找出最近的几个体检机构。 将最近的几个体检机构显示在 Google Map 上的 Marker 上,并在 Marker 上显示它们的名称和地址。 当用户点击这些 Marker 时,显示有关体检机构的更多详细信息。这些步骤的详细代码
时间: 2023-06-24 07:07:10 浏览: 176
1. 添加权限和依赖项
在 AndroidManifest.xml 文件中添加以下权限:
```xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
```
在 app 的 build.gradle 文件中添加以下依赖项:
```groovy
dependencies {
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.0.0'
}
```
2. 创建 Google Maps API 密钥
请按照 [Google Maps Platform 文档](https://developers.google.com/maps/gmp-get-started#create-project) 中的指示创建和启用 Google Maps API 密钥。
3. 在布局文件中添加 MapView
在布局文件中添加 MapView 控件:
```xml
<com.google.android.gms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
```
4. 初始化 Google Map
在 Activity 或 Fragment 中创建 MapView 对象,并在 onCreate 方法中调用以下方法初始化 Google Map:
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 创建 MapView 对象
val mapView = findViewById<MapView>(R.id.mapView)
// 在 onCreate 方法中调用以下方法初始化 Google Map
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { googleMap ->
// 在这里初始化 Google Map
}
}
```
5. 获取用户当前位置
在 onCreate 方法中获取用户当前位置:
```kotlin
// 获取 LocationManager 对象
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 检查是否有定位权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有定位权限则请求
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
),
REQUEST_LOCATION_PERMISSION
)
return
}
// 获取最后已知的位置
val lastLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
// 如果有最后已知的位置则显示在地图上
lastLocation?.let { location ->
val latLng = LatLng(location.latitude, location.longitude)
googleMap.addMarker(MarkerOptions().position(latLng).title("You are here"))
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13f))
}
```
6. 显示附近的体检机构
使用 Retrofit 和 Google Places API 获取附近的体检机构:
```kotlin
private fun getNearbyClinics(latLng: LatLng) {
// 创建 Retrofit 对象
val retrofit = Retrofit.Builder()
.baseUrl("https://maps.googleapis.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
// 创建 Places API 服务
val service = retrofit.create(PlacesService::class.java)
// 调用 Places API 的 nearbysearch 方法获取附近的体检机构
val call = service.nearbysearch(
"clinic",
latLng.latitude.toString() + "," + latLng.longitude.toString(),
5000, // 搜索半径
"zh-CN", // 语言
BuildConfig.GOOGLE_MAPS_API_KEY // Google Maps API 密钥
)
// 处理 API 响应
call.enqueue(object : Callback<PlacesResponse> {
override fun onResponse(call: Call<PlacesResponse>, response: Response<PlacesResponse>) {
if (response.isSuccessful) {
// 在地图上添加 Marker
response.body()?.results?.forEach { result ->
val latLng = LatLng(result.geometry.location.lat, result.geometry.location.lng)
googleMap.addMarker(
MarkerOptions()
.position(latLng)
.title(result.name)
.snippet(result.vicinity)
)
}
} else {
// 处理 API 调用错误
}
}
override fun onFailure(call: Call<PlacesResponse>, t: Throwable) {
// 处理网络连接错误
}
})
}
```
其中,PlacesService 是使用 Retrofit 创建的 API 服务:
```kotlin
interface PlacesService {
@GET("/maps/api/place/nearbysearch/json")
fun nearbysearch(
@Query("type") type: String,
@Query("location") location: String,
@Query("radius") radius: Int,
@Query("language") language: String,
@Query("key") apiKey: String
): Call<PlacesResponse>
}
```
PlacesResponse 是 API 响应的 POJO 类:
```kotlin
data class PlacesResponse(
val results: List<PlaceResult>,
val status: String
)
data class PlaceResult(
val geometry: Geometry,
val name: String,
val vicinity: String
)
data class Geometry(
val location: Location
)
data class Location(
val lat: Double,
val lng: Double
)
```
7. 计算距离并找到最近的几个体检机构
使用 Location.distanceBetween 方法计算用户位置和体检机构位置之间的距离,并使用 Collections.sort 方法按距离排序:
```kotlin
private fun getNearbyClinics(latLng: LatLng) {
// ...
// 处理 API 响应
call.enqueue(object : Callback<PlacesResponse> {
override fun onResponse(call: Call<PlacesResponse>, response: Response<PlacesResponse>) {
if (response.isSuccessful) {
// 在地图上添加 Marker
val markers = mutableListOf<Marker>()
response.body()?.results?.forEach { result ->
val location = Location(LocationManager.NETWORK_PROVIDER)
location.latitude = result.geometry.location.lat
location.longitude = result.geometry.location.lng
val distance = FloatArray(1)
Location.distanceBetween(
latLng.latitude,
latLng.longitude,
location.latitude,
location.longitude,
distance
)
markers.add(
googleMap.addMarker(
MarkerOptions()
.position(LatLng(location.latitude, location.longitude))
.title(result.name)
.snippet(result.vicinity)
)
)
}
// 按距离排序并显示最近的几个体检机构
markers.sortBy { it.position.distanceTo(latLng) }
markers.take(3).forEach {
it.showInfoWindow()
}
} else {
// 处理 API 调用错误
}
}
override fun onFailure(call: Call<PlacesResponse>, t: Throwable) {
// 处理网络连接错误
}
})
}
```
8. 显示体检机构的详细信息
为每个 Marker 添加 OnInfoWindowClickListener 监听器,在用户点击 Marker 时显示体检机构的详细信息:
```kotlin
private fun getNearbyClinics(latLng: LatLng) {
// ...
// 处理 API 响应
call.enqueue(object : Callback<PlacesResponse> {
override fun onResponse(call: Call<PlacesResponse>, response: Response<PlacesResponse>) {
if (response.isSuccessful) {
// 在地图上添加 Marker
val markers = mutableListOf<Marker>()
response.body()?.results?.forEach { result ->
val location = Location(LocationManager.NETWORK_PROVIDER)
location.latitude = result.geometry.location.lat
location.longitude = result.geometry.location.lng
val distance = FloatArray(1)
Location.distanceBetween(
latLng.latitude,
latLng.longitude,
location.latitude,
location.longitude,
distance
)
markers.add(
googleMap.addMarker(
MarkerOptions()
.position(LatLng(location.latitude, location.longitude))
.title(result.name)
.snippet(result.vicinity)
.tag(result.place_id) // 添加 place_id 作为标记
)
)
}
// 按距离排序并显示最近的几个体检机构
markers.sortBy { it.position.distanceTo(latLng) }
markers.take(3).forEach { marker ->
marker.showInfoWindow()
marker.setOnInfoWindowClickListener {
// 显示体检机构的详细信息
val placeId = it.tag as String
val intent = Intent(this@MainActivity, ClinicActivity::class.java)
intent.putExtra("placeId", placeId)
startActivity(intent)
}
}
} else {
// 处理 API 调用错误
}
}
override fun onFailure(call: Call<PlacesResponse>, t: Throwable) {
// 处理网络连接错误
}
})
}
```
其中,ClinicActivity 是用于显示体检机构详细信息的 Activity。在 onCreate 方法中获取传递过来的 place_id,然后使用 Retrofit 和 Google Places API 获取体检机构的详细信息并显示:
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_clinic)
// 获取传递过来的 place_id
val placeId = intent.getStringExtra("placeId")
// 创建 Retrofit 对象
val retrofit = Retrofit.Builder()
.baseUrl("https://maps.googleapis.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
// 创建 Places API 服务
val service = retrofit.create(PlacesService::class.java)
// 调用 Places API 的 details 方法获取体检机构详细信息
val call = service.details(
placeId,
"zh-CN", // 语言
BuildConfig.GOOGLE_MAPS_API_KEY // Google Maps API 密钥
)
// 处理 API 响应
call.enqueue(object : Callback<PlaceDetailsResponse> {
override fun onResponse(
call: Call<PlaceDetailsResponse>,
response: Response<PlaceDetailsResponse>
) {
if (response.isSuccessful) {
// 显示体检机构的详细信息
response.body()?.result?.let { result ->
titleTextView.text = result.name
ratingBar.rating = result.rating.toFloat()
addressTextView.text = result.formatted_address
phoneTextView.text = result.formatted_phone_number
websiteTextView.text = result.website
}
} else {
// 处理 API 调用错误
}
}
override fun onFailure(call: Call<PlaceDetailsResponse>, t: Throwable) {
// 处理网络连接错误
}
})
}
```
其中,PlaceDetailsResponse 是 API 响应的 POJO 类:
```kotlin
data class PlaceDetailsResponse(
val result: PlaceDetailsResult,
val status: String
)
data class PlaceDetailsResult(
val name: String,
val rating: Double,
val formatted_address: String,
val formatted_phone_number: String,
val website: String
)
```
阅读全文