我尝试在我的应用程序中使用 Mapbox,但遇到一些问题。我的代码如下所示:
首页片段:
@AndroidEntryPoint
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding: FragmentHomeBinding get() = _binding!!
private lateinit var onBackPressedCallback: OnBackPressedCallback
private val viewModel: HomeViewModel by viewModels()
private lateinit var map: GoogleMap
private lateinit var mapView: MapView
private lateinit var locationComponentPlugin: LocationComponentPlugin
private val markersManager = MarkersManager()
private val routesManager = RoutesManager()
private val onIndicatorBearingChangedListener = OnIndicatorBearingChangedListener {
mapView.mapboxMap.setCamera(CameraOptions.Builder().bearing(it).build())
}
private val onIndicatorPositionChangedListener = OnIndicatorPositionChangedListener {
mapView.mapboxMap.setCamera(CameraOptions.Builder().center(it).build())
mapView.gestures.focalPoint = mapView.mapboxMap.pixelForCoordinate(it)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapboxOptions.accessToken = requireContext().getString(R.string.mapbox_access_token)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupMap()
setupView()
setupOnBackPress()
setupViewModelSubscriptions()
}
override fun onResume() {
super.onResume()
val missingPermissions = PermissionUtils.checkPermissions(requireContext(), neededPermissions)
if (missingPermissions.isNotEmpty()) {
findNavController()
.navigate(R.id.action_homeFragment_to_missingPermissionsFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
onBackPressedCallback.remove()
_binding = null
}
private fun setupView() {
binding.btnManageCars.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_manageCarsFragment)
}
binding.btnPlaceCar.setOnClickListener {
onPlaceClicked()
}
binding.btnStartNavi.setOnClickListener {
viewModel.onEvent(HomeEvent.StartNavigation)
}
binding.btnCancelNavi.setOnClickListener {
viewModel.onEvent(HomeEvent.CancelNavigation)
}
}
private fun setupMap() {
mapView = MapView(requireContext())
mapView.mapboxMap.loadStyle(Style.STANDARD)
initLocationComponent()
}
private fun initLocationComponent() {
locationComponentPlugin = mapView.location
locationComponentPlugin.updateSettings {
puckBearing = PuckBearing.COURSE
puckBearingEnabled = true
enabled = true
locationPuck = LocationPuck2D(
bearingImage = ImageHolder.from(com.mapbox.maps.R.drawable.mapbox_user_puck_icon),
shadowImage = ImageHolder.from(com.mapbox.maps.R.drawable.mapbox_user_icon_shadow),
scaleExpression = interpolate {
linear()
zoom()
stop {
literal(0.0)
literal(0.6)
}
stop {
literal(20.0)
literal(1.0)
}
}.toJson()
)
}
locationComponentPlugin.addOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
locationComponentPlugin.addOnIndicatorBearingChangedListener(onIndicatorBearingChangedListener)
}
private fun setupOnBackPress() {
onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
this.isEnabled = false
requireActivity().onBackPressedDispatcher.onBackPressed()
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback)
}
private fun setupViewModelSubscriptions() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.lastLocation.collectLatest { location ->
location?.let {
updateUserLocation(it)
}
}
}
launch {
viewModel.oneTimeEvent.collect { event ->
manageOneTimeEvent(event)
}
}
}
}
private fun updateUserLocation(location: Location) {
mapView.mapboxMap.setCamera(
CameraOptions.Builder()
.center(Point.fromLngLat(location.longitude, location.latitude))
.zoom(25.0)
.build()
)
}
}
HomeView模型:
@HiltViewModel
class HomeViewModel @Inject constructor(
private val startLocationUpdatesUseCase: StartLocationUpdatesUseCase,
private val stopLocationUpdatesUseCase: StopLocationUpdatesUseCase,
private val getCurrentLocationUseCase: GetCurrentLocationUseCase,
private val getAllCarsUseCase: GetAllCarsUseCase,
private val getPlacedCarsUseCase: GetPlacedCarsUseCase,
private val startNavigationUseCase: StartNavigationUseCase,
private val setCarLocationUseCase: SetCarLocationUseCase,
private val removeCarLocationUseCase: RemoveCarLocationUseCase,
) : ViewModel() {
val lastLocation: StateFlow<Location?> = getCurrentLocationUseCase()
private val _uiState = MutableStateFlow(HomeState())
val uiState: StateFlow<HomeState> = _uiState.asStateFlow()
private val _oneTimeEvent = MutableSharedFlow<HomeOneTimeEvent>()
val oneTimeEvent: SharedFlow<HomeOneTimeEvent> = _oneTimeEvent.asSharedFlow()
init {
startLocationUpdatesUseCase()
onEvent(HomeEvent.GetUserCars)
onEvent(HomeEvent.GetPlacedCars)
}
...
...
...
}
使用案例:
class StartLocationUpdatesUseCase@Inject constructor(
private val repository: LocationRepository
) {
operator fun invoke() {
repository.startLocationUpdates()
}
}
class StopLocationUpdatesUseCase @Inject constructor(
private val repository: LocationRepository
) {
operator fun invoke() = repository.stopLocationUpdates()
}
class GetCurrentLocationUseCase @Inject constructor(
private val repository: LocationRepository
) {
operator fun invoke(): StateFlow<Location?> = repository.currentLocation
}
存储库:
class LocationRepositoryImpl @Inject constructor(
private val deviceLocationProvider: DeviceLocationProvider
) : LocationRepository {
private val _currentLocation = MutableStateFlow<Location?>(null)
override val currentLocation: StateFlow<Location?> = _currentLocation.asStateFlow()
private val locationObserver = LocationObserver { locations ->
_currentLocation.value = locations.lastOrNull()
}
override fun startLocationUpdates() {
deviceLocationProvider.addLocationObserver(locationObserver)
}
override fun stopLocationUpdates() {
deviceLocationProvider.removeLocationObserver(locationObserver)
}
}
和定位模块
@Module
@InstallIn(SingletonComponent::class)
class LocationModule {
@Provides
fun provideDeviceLocationProvider(): DeviceLocationProvider {
val locationService = LocationServiceFactory.getOrCreate()
val request = LocationProviderRequest.Builder()
.interval(IntervalSettings.Builder().interval(1000L).minimumInterval(1000L).maximumInterval(5000L).build())
.displacement(0f)
.accuracy(AccuracyLevel.HIGHEST)
.build()
val result = locationService.getDeviceLocationProvider(request)
if (result.isValue) {
return result.value!!
} else {
throw IllegalStateException("Cannot obtain DeviceLocationProvider: ${result.error?.message ?: "Unknown error"}")
}
}
}
由于某些未知原因,我无法在地图上看到用户,甚至无法在位置更新时更改相机。当前的行为是应用程序在启动时显示地图并且没有任何变化。我什至可以更改地图样式,但这也没有任何作用。有谁知道可能是什么问题?
private fun setupMap() {
mapView = MapView(requireContext())
mapView.mapboxMap.loadStyle(Style.STANDARD)
initLocationComponent()
}
在这里,您正在创建一个
MapView
小部件,为其配置样式,然后将其丢弃。特别是,它没有出现在 UI 中,因为您没有执行任何操作将其放入 UI 中。
当前行为是应用程序在启动时显示地图
这意味着您在某个地方有另一个
MapView
,也许在 fragment_home.xml
中,您应该通过 FragmentHomeBinding
使用。因此,使用该 MapView
并删除您在 setupMap()
中创建的那个。