市内用车难点
- 附近车辆查询
- 司机线路规划
- 司机路径规划同步乘客端
- 实际行走轨迹、距离及时间
- 价格实时同步
实现所需SDK
说明:通过高德的免费api实现以上功能,需后台配合,后台不大懂得。。。自己查api去哇
Android接入高德SDK内容
需要地图定位导航猎鹰功能
- 其中地图功能提供附近派单功能,用于上报司机位置,为了后台给用户附近派单功能服务
- 定位功能实现司机及乘客的定位获取GPS数据,为乘客端显示车头方向以及下单乘客位置进行服务
- 导航,司机端通过规划线路展示导航完成订单流程,乘客端用司机端GPS数据接入外部数据进行实现司机端位置在乘客端显示的功能
- 猎鹰功能,司机端启动猎鹰,为实际行驶路径以及价格计算等功能进行服务,订单完成后可看订单行驶轨迹
具体功能实现
1. 附近车辆查询及位置上报
高德附近派单位置上报采坑:
- 如果位置不动经纬度获取到的与上次上报的经纬度相同会出现上报失败的问题
- 位置上报的用户标识需唯一
mNearbySearch = NearbySearch.getInstance(applicationContext)
mNearbySearch!!.startUploadNearbyInfoAuto({
val loadInfo = UploadInfo()
loadInfo.coordType = NearbySearch.AMAP
//位置信息
var la = LatLonPoint(BaseApplication.lat, BaseApplication.lon)
if (lastLatLonPoint.latitude == la.latitude && lastLatLonPoint.longitude == la.longitude) {
la.latitude += 0.000001
la.longitude += 0.000001
}
lastLatLonPoint = la
loadInfo.point = lastLatLonPoint
loadInfo.userID = BaseApplication.driver_id
loadInfo
}, 10000)
mNearbySearch!!.addNearbyListener(this)
对上次上报位置进行对比,如果经纬度相同做处理使位置可上报成功
后台根据SDK搜索时间段内上报位置司机进行半径筛选,筛选出符合的司机进行派单
2. 司机线路规划
司机线路规划踩坑
司机规划线路全部为通过导航的线路规划
自定义UI需要关闭自动规划路线的功能,所以在判断路径偏移时有可能出现多条规划线路的问题,开始使用map.clear()的方法,但这个方法只能清除marker以及自身位置图标等覆盖图层,无法清除路线,需将RouteOverLay作为全局变量偏离重算时需destroy并重新初始化地图
if (routeOverlay != null) {
map.displayOverview()
routeOverlay!!.destroy()
routeOverlay = null
initMap()
}
3. 司机路径规划同步乘客端
路径规划同步到乘客端的时候,想过好几种方案
1.直接给后台路径点,后台再通过长连接告诉乘客端,绘制出线路,但是这种方法在距离较长时数据量比较大,并且在路径偏移时重新上传偏移后的路径点再通知乘客端,数据量以及每次的数据交互重复性太多,没有采用。
2.给后台路径途经点的部分数据,让乘客端画线路实现线路同步,再由后台推送司机位置将司机位置画在地图上,这种方式,司机的图片画可能和路径的线不在一起,导致司机的位置图标在线的旁边显示
3.最后确定方案为:将线路途经点做等分取16个点,推送后台,后台推送乘客端,由乘客端通过导航的路径规划将十六个点作为导航途经点规划线路。但是这种的问题是,在线路特别短的情况下,可能取不到16个点,需要在司机端做点数量的处理,然后在乘客端的导航中传入司机定位的GPS数据(此数据为司机推送给后台,后台通过长连接的方式又推送给乘客),使用外部GPS数据来实现司机路径规划同步乘客端,并将司机的行驶情况同步在乘客端,并在onNaviInfoUpdate中获取算路公里数以及预计时间,同步到乘客端。完成司乘同显的问题
获取司机导航路径规划的点数组
mAMapNavi!!.naviPath.coordList
获取司机规划路线剩余距离
override fun onNaviInfoUpdate(naviinfo: NaviInfo?) {
naviinfo!!.pathRetainDistance//单位是米
}
获取司机规划路线预计时间
override fun onNaviInfoUpdate(naviinfo: NaviInfo?) {
naviinfo.pathRetainTime//单位是分钟
}
4. 实际行走轨迹、距离及时间
高德猎鹰轨迹同步
private fun startTrack() {
val trackParam = TrackParam(Constant.TRACK_SERVER_ID, BaseApplication.amap_terminal_id)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
trackParam.notification = createNotification()
}
aMapTrackClient.startTrack(trackParam, onTrackListener)
}
其中TRACK_SERVER_ID为猎鹰服务ID
amap_terminal_id为与司机绑定的服务ID
轨迹上报的监听方法
private val onTrackListener = object : SimpleOnTrackLifecycleListener() {
/**
* 定位采集开启情况
*/
override fun onStartGatherCallback(status: Int, msg: String?) {
when (status) {
ErrorCode.TrackListen.START_GATHER_SUCEE -> {
isGatherRunning = true
Log.e(TAG, "定位采集开启成功")
}
ErrorCode.TrackListen.START_GATHER_ALREADY_STARTED -> {
Log.e(TAG, "定位采集已经开启")
isGatherRunning = true
}
else -> {
Log.e(TAG, "error onStartGatherCallback, status: $status, msg: $msg")
}
}
}
/**
* 定位采集关闭
*/
override fun onStopGatherCallback(status: Int, msg: String?) {
if (status == ErrorCode.TrackListen.STOP_GATHER_SUCCE) {
Toast.makeText(this@OrderControlActivity, "定位采集停止成功", Toast.LENGTH_SHORT).show()
isGatherRunning = false
} else {
Log.w(TAG, "error onStopGatherCallback, status: $status, msg: $msg")
}
}
/**
* 轨迹上报开启情况
*/
override fun onStartTrackCallback(status: Int, msg: String?) {
when (status) {
ErrorCode.TrackListen.START_TRACK_SUCEE, ErrorCode.TrackListen.START_TRACK_SUCEE_NO_NETWORK -> {
// 成功启动
Log.e(TAG, "启动服务成功")
isServiceRunning = true
aMapTrackClient.trackId = trackId
aMapTrackClient.startGather(this)
}
ErrorCode.TrackListen.START_TRACK_ALREADY_STARTED -> {
// 已经启动
Log.e(TAG, "服务已经启动")
isServiceRunning = true
aMapTrackClient.trackId = trackId
aMapTrackClient.startGather(this)
}
else -> {
Log.e(TAG, "error onStartTrackCallback, status: $status, msg: $msg")
}
}
}
/**
* 轨迹上报停止
*/
override fun onStopTrackCallback(status: Int, msg: String?) {
if (status == ErrorCode.TrackListen.STOP_TRACK_SUCCE) {
// 成功停止
Toast.makeText(this@OrderControlActivity, "停止服务成功", Toast.LENGTH_SHORT).show()
isServiceRunning = false
isGatherRunning = false
} else {
Toast.makeText(
this@OrderControlActivity,
"error onStopTrackCallback, status: $status, msg: $msg",
Toast.LENGTH_LONG
).show()
}
}
}
轨迹部分没什么坑,高德的DEMO写的很明白
后台根据轨迹可以计算司机的行驶距离以及行驶时长自行计算价格
5. 价格实时同步
后台根据轨迹以及计价规则计算价格,通过长连接同步到司机以及乘客,没什么好说的,能算出来推就好了