Android——实现APP内算路导航
百度地图API算路导航
- 效果视频
- 跳转至百度地图进行算路导航
- APP内进行算路导航
- 功能实现
- 跳转方式实现
- 权限声明
- 判断手机内是否安装百度地图
- 实现跳转至百度地图
- 非跳转方式实现
- UI设计
- 背景
- 圆点
- 布局代码
- 功能实现
- 权限声明
- 初始化BroadCast
- 初始化车辆信息
- 初始化节点信息
- 节点信息交换
- 地址信息转地理信息(经纬度)
- 保存地理信息
- 算路导航
- 销毁
效果视频
跳转至百度地图进行算路导航
APP内进行算路导航
功能实现
跳转方式实现
功能描述:通过初始化百度地图API,获取当前位置的经纬度做为起点,所输入的地址做为目的地,然后封装成Uri格式,使用隐式Intent调用百度地图APP,最终实现算路导航。
权限声明
声明导航所需要具备的权限,例如:网路权限、位置权限等
private void InitPermission(){List PermissionList = new ArrayList<>();//判断权限是否授权if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) {PermissionList.add( Manifest.permission.ACCESS_FINE_LOCATION );}if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.READ_PHONE_STATE ) != PackageManager.PERMISSION_GRANTED) {PermissionList.add( Manifest.permission.READ_PHONE_STATE );}if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.WRITE_EXTERNAL_STORAGE ) != PackageManager.PERMISSION_GRANTED) {PermissionList.add( Manifest.permission.WRITE_EXTERNAL_STORAGE );}if (!PermissionList.isEmpty()) {String[] Permissions = PermissionList.toArray( new String[PermissionList.size()] );//转化为数组ActivityCompat.requestPermissions( Function.this, Permissions, 1 );//一次性申请权限} else {/*****************如果权限都已经声明,开始配置参数*****************/requestLocation();}}
判断手机内是否安装百度地图
百度地图包名
public static final String BAIDUMAPPACKAGE = "com.baidu.BaiduMap"; // 百度地图包名
通过以百度地图包名为索引,查找手机内是否存在该应用,并返回boolean值
public static boolean isBaiduMapInstalled(){return isInstallPackage(BAIDUMAPPACKAGE);}private static boolean isInstallPackage(String packageName) {return new File("/data/data/" + packageName).exists();}
实现跳转至百度地图
以获取自身的经纬度为导航起点,以输入的地址做为导航终点。最后通过Intent隐式跳转,唤起百度地图APP
public void Navigation(String EndAddress){Uri uri = Uri.parse( "baidumap://map/direction?origin=" + Latitude + "," + Longitude + "&" + "destination=" + EndAddress + "&mode=driving&package=com.baidu.BaiduMap;end" );startActivity( new Intent( Intent.ACTION_VIEW, uri ) );}
非跳转方式实现
功能描述:首先通过将输入的地址转为经纬度形式,然后通过百度地图导航API进行算路节点计算,然后完成导航规划
UI设计
背景
在drawable目录下创建一个文件,并实现一个圆角矩形
圆点
在drawable目录下创建一个文件,并实现一个实心圆
布局代码
功能实现
在介绍功能前,首先先介绍两个概念,即地理编码与反地理编码
具体介绍请跳转至百度地图官网
地理编码:地址信息转换为地理坐标(经纬度)
反地理编码:地理坐标(经纬度)转换为地址信息
权限声明
将所需要声明的权限列为一个数组
private static final String[] authBaseArr = {Manifest.permission.RECORD_AUDIO,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS,Manifest.permission.WRITE_EXTERNAL_STORAGE};
遍历数组,判断权限是否声明,并返回boolean值做为判断标识符
private void InitPermission() {// 申请权限if (Build.VERSION.SDK_INT >= 23) {if (!hasBasePhoneAuth()) {requestPermissions(authBaseArr, authBaseRequestCode);}}}private boolean hasBasePhoneAuth() {PackageManager pm = this.getPackageManager();for (String auth : authBaseArr) {if (pm.checkPermission(auth, this.getPackageName()) != PackageManager.PERMISSION_GRANTED) {return false;}}return true;}
初始化BroadCast
private void InitBroadCastReceiver() {IntentFilter filter = new IntentFilter();filter.addAction("com.navi.ready");mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {BNDemoFactory.getInstance().initCarInfo();BNDemoFactory.getInstance().initRoutePlanNode();}};registerReceiver(mReceiver, filter);}
初始化车辆信息
若没有手动修改车辆信息,则以如下信息为基础
public void initCarInfo() {// 驾车车牌设置// BaiduNaviManagerFactory.getCommonSettingManager().setCarNum("京A88888");// 货车信息BNTruckInfo truckInfo = new BNTruckInfo.Builder().plate("京A88888").axlesNumber(2).axlesWeight(1).emissionLimit(VehicleConstant.EmissionStandard.S3).length(5).weight(2).loadWeight(1).oilCost("40000").plateType(VehicleConstant.PlateType.BLUE).powerType(VehicleConstant.PowerType.OIL).truckType(VehicleConstant.TruckType.HEAVY).height(2).width(2.5f).build();// 该接口会做本地持久化,在应用中设置一次即可BaiduNaviManagerFactory.getCommonSettingManager().setTruckInfo(truckInfo);// 摩托车信息BNMotorInfo motorInfo = new BNMotorInfo.Builder().plate("京A88888").plateType(VehicleConstant.PlateType.BLUE).motorType(VehicleConstant.MotorType.OIL).displacement("").build();// 该接口会做本地持久化,在应用中设置一次即可BaiduNaviManagerFactory.getCommonSettingManager().setMotorInfo(motorInfo);// BaiduNaviManagerFactory.getCommonSettingManager().setTestEnvironment(false);BaiduNaviManagerFactory.getCommonSettingManager().setNodeClick(true);}
初始化节点信息
若没有手动修改路径节点信息,则以如下信息为基础
public void initRoutePlanNode() {startNode = new BNRoutePlanNode.Builder().latitude(40.041690).longitude(116.306333).name("百度大厦").description("百度大厦").build();endNode = new BNRoutePlanNode.Builder().latitude(39.908560).longitude(116.397609).name("北京天安门").description("北京天安门").build();}
节点信息交换
即将起点地址信息与终点地址信息完成互换,利用一个临时变量存储一方数据,完成互换
public void ExchangeStr(View view) {String Start = startAddress.getText().toString().trim();String End = endAddress.getText().toString().trim();startAddress.setText( End );endAddress.setText( Start );}
地址信息转地理信息(经纬度)
Geocoder为百度地图提供的一个地址信息与地理信息相互转换的一个API
geocoder = new Geocoder( SelectNodeActivity.this );
通过用户键入的地址信息,由getFromLocationName()方法进行转换,并返回一个Address对象;需要注意的是键入的地址信息应当较为精准,例如xxx省xxx市xxx区xxx地,这样所转换的地理信息,精度才不会偏移太大
private String GetNodeValue(String Address){builder = new StringBuilder( );try {List addresses = geocoder.getFromLocationName(Address,1 );double start_latitude = addresses.get( 0 ).getLatitude();//纬度double start_longitude = addresses.get( 0 ).getLongitude();//经度builder.append( start_longitude ).append( "," ).append( start_latitude );} catch (IOException e) {Toast.makeText( SelectNodeActivity.this,"error",Toast.LENGTH_SHORT).show();e.printStackTrace();}return builder.toString();}
保存地理信息
通过使用一个简单工厂单例类保存所转换的地理信息(经纬度)
private void AddrToCoordinate(){boolean flag = Geocoder.isPresent();if (!flag)Toast.makeText( SelectNodeActivity.this,"error",Toast.LENGTH_SHORT ).show();else {String start = GetNodeValue(startAddress.getText().toString().trim());String end = GetNodeValue(endAddress.getText().toString().trim());//TODO 设置起点经纬度if (!TextUtils.isEmpty(start)) {BNDemoFactory.getInstance().setStartNode(this, start);Log.d( "start:",start );}//TODO 设置终点经纬度if (!TextUtils.isEmpty(end)) {BNDemoFactory.getInstance().setEndNode(this, end);Log.d( "end:",end );}}}
算路导航
private void routePlanToNavi(final Bundle bundle) {List list = new ArrayList<>();//TODO 在主函数中获取经纬度,开始算路导航list.add(BNDemoFactory.getInstance().getStartNode(this));list.add(BNDemoFactory.getInstance().getEndNode(this));// 关闭电子狗if (BaiduNaviManagerFactory.getCruiserManager().isCruiserStarted()) {BaiduNaviManagerFactory.getCruiserManager().stopCruise();}BaiduNaviManagerFactory.getRoutePlanManager().routePlanToNavi(list,IBNRoutePlanManager.RoutePlanPreference.ROUTE_PLAN_PREFERENCE_DEFAULT,bundle, handler);}
节点计算需要耗不少的内存空间以及时间,故使用异步通信,不影响主线程的分发以及UI的刷新
private Handler handler = new Handler( Looper.getMainLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what) {case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_START:Toast.makeText(SelectNodeActivity.this, "算路开始", Toast.LENGTH_SHORT).show();ControlBoardWindow.getInstance().showControl("算路开始");break;case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_SUCCESS:Toast.makeText(SelectNodeActivity.this, "算路成功", Toast.LENGTH_SHORT).show();ControlBoardWindow.getInstance().showControl("算路成功");// 躲避限行消息Bundle infoBundle = (Bundle) msg.obj;if (infoBundle != null) {String info = infoBundle.getString( BNaviCommonParams.BNRouteInfoKey.TRAFFIC_LIMIT_INFO);Log.e("OnSdkDemo", "info = " + info);}break;case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_FAILED:ControlBoardWindow.getInstance().showControl("算路失败");Toast.makeText(SelectNodeActivity.this.getApplicationContext(),"算路失败", Toast.LENGTH_SHORT).show();break;case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_TO_NAVI:Toast.makeText(SelectNodeActivity.this.getApplicationContext(),"算路成功准备进入导航", Toast.LENGTH_SHORT).show();ControlBoardWindow.getInstance().showControl("算路成功准备进入导航");switch (mPageType) {case BNDemoUtils.NORMAL:BNDemoUtils.gotoNavi(SelectNodeActivity.this);break;case BNDemoUtils.ANALOG:BNDemoUtils.gotoAnalog(SelectNodeActivity.this);break;case BNDemoUtils.EXTGPS:BNDemoUtils.gotoExtGps(SelectNodeActivity.this);break;default:break;}break;default:break;}}};
销毁
当使用完成之后,应该将可销毁的内容放入onDestroy内,避免内存空间的浪费
@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(mReceiver);stopService(new Intent(this, ForegroundService.class));}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
