Effect video
Jump to Baidu map for route calculation and navigation
Route calculation and navigation in APP
Function realization
Jump mode implementation
Function Description: by initializing Baidu map API, obtain the longitude and latitude of the current position as the starting point, and the entered address as the destination, then package it into Uri format, use implicit Intent to call Baidu map APP, and finally realize routing navigation.
Permission statement
Declare the permissions required for navigation, such as network permissions, location permissions, etc
private void InitPermission(){ List<String> PermissionList = new ArrayList<>(); //Judge whether the permission is authorized 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()] );//Convert to array ActivityCompat.requestPermissions( Function.this, Permissions, 1 );//One time application authority } else { /*****************If the permissions have been declared, start configuring parameters*****************/ requestLocation(); } }
Determine whether Baidu map is installed in the mobile phone
Baidu map package name
public static final String BAIDUMAPPACKAGE = "com.baidu.BaiduMap"; // Baidu map package name
By taking the baidu map package name as the index, find out whether the application exists in the mobile phone, and return the boolean value
public static boolean isBaiduMapInstalled(){ return isInstallPackage(BAIDUMAPPACKAGE); } private static boolean isInstallPackage(String packageName) { return new File("/data/data/" + packageName).exists(); }
Jump to Baidu map
Take the longitude and latitude obtained as the navigation starting point and the entered address as the navigation ending point. Finally, evoke Baidu map APP through Intent implicit jump
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 ) ); }
Non jump mode implementation
Function Description: first, convert the input address into latitude and longitude, then calculate the routing node through Baidu map navigation API, and then complete the navigation planning
UI design
background
Create a file in the drawable directory and implement a rounded rectangle<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#ffffff"/> <corners android:radius="10dp"/> </shape>
Dot
Create a file in the drawable directory and implement a solid circle<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#4CAF50"/> <size android:height="10dp" android:width="10dp"/>
Layout code
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Activity.SelectNodeActivity" android:orientation="vertical" android:background="#F1EDED"> <include layout="@layout/titlebar"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@drawable/white_radiu_bg"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/grey_radiu_bg" android:layout_margin="20dp" android:padding="10dp"> <LinearLayout android:layout_width="0dp" android:layout_weight="7" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="@dimen/navi_dimens_5dp"> <View android:layout_width="10dp" android:layout_height="10dp" android:background="@drawable/green_point" android:layout_gravity="center" android:layout_marginRight="5dp"/> <EditText android:id="@+id/startAddress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="please enter starting point" android:textColor="#000000" android:textSize="15sp" android:layout_gravity="center" android:layout_marginLeft="5dp" android:background="@null"/> </LinearLayout> <!--Split line--> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#DBCACA" android:layout_marginTop="5dp" android:layout_marginBottom="5dp"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="@dimen/navi_dimens_5dp"> <View android:layout_width="10dp" android:layout_height="10dp" android:background="@drawable/red_point" android:layout_gravity="center" android:layout_marginRight="5dp"/> <EditText android:id="@+id/endAddress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="please enter ending point" android:textColor="#000000" android:textSize="15sp" android:layout_marginLeft="5dp" android:background="@null" android:layout_gravity="center"/> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/exchangeStr" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center" android:layout_marginLeft="10dp" android:onClick="ExchangeStr"> <ImageView android:layout_width="25dp" android:layout_height="25dp" android:src="@drawable/icon_exchange" android:layout_gravity="center"/> </LinearLayout> </LinearLayout> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="50dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/white_radiu_bg" android:layout_margin="10dp" android:padding="10dp" android:layout_alignParentBottom="true"> <Button android:id="@+id/exeProcess" android:layout_width="match_parent" android:layout_height="30dp" android:background="@drawable/green_radiu_bg" android:text="Start Navigation" android:textAllCaps="false" android:textColor="#ffffff" android:layout_margin="10dp" android:onClick="ExeProcess"/> </LinearLayout> </RelativeLayout> </LinearLayout>
Function realization
Before introducing the function, first introduce two concepts, namely geocoding and anti geocoding
For details, please jump to the official website of Baidu map
Geocoding:Converting address information to geographic coordinates(Longitude and latitude)
Anti geocoding:Geographical coordinates(Longitude and latitude)Convert to address information
Permission statement
List the required declared permissions as an array
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 };
Traverse the array to determine whether the permission is declared, and return the boolean value as the judgment identifier
private void InitPermission() { // Apply for permission 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; }
Initialize BroadCast
private void InitBroadCastReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction("com.navi.ready"); mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { BNDemoFactory.getInstance().initCarInfo(); BNDemoFactory.getInstance().initRoutePlanNode(); } }; registerReceiver(mReceiver, filter); }
Initialize vehicle information
If the vehicle information is not modified manually, it shall be based on the following information
public void initCarInfo() { // Driving license plate setting // BaiduNaviManagerFactory.getCommonSettingManager().setCarNum("Jing A88888"); // Truck information BNTruckInfo truckInfo = new BNTruckInfo.Builder() .plate("Beijing 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(); // The interface will be locally persistent and can be set once in the application BaiduNaviManagerFactory.getCommonSettingManager().setTruckInfo(truckInfo); // Motorcycle information BNMotorInfo motorInfo = new BNMotorInfo.Builder() .plate("Beijing A88888") .plateType(VehicleConstant.PlateType.BLUE) .motorType(VehicleConstant.MotorType.OIL) .displacement("") .build(); // The interface will be locally persistent and can be set once in the application BaiduNaviManagerFactory.getCommonSettingManager().setMotorInfo(motorInfo); // BaiduNaviManagerFactory.getCommonSettingManager().setTestEnvironment(false); BaiduNaviManagerFactory.getCommonSettingManager().setNodeClick(true); }
Initialize node information
If the path node information is not modified manually, it is based on the following information
public void initRoutePlanNode() { startNode = new BNRoutePlanNode.Builder() .latitude(40.041690) .longitude(116.306333) .name("Baidu building") .description("Baidu building") .build(); endNode = new BNRoutePlanNode.Builder() .latitude(39.908560) .longitude(116.397609) .name("Beijing Tiananmen") .description("Beijing Tiananmen") .build(); }
Node information exchange
That is, the start address information and the end address information are exchanged, and a temporary variable is used to store one party's data to complete the exchange
public void ExchangeStr(View view) { String Start = startAddress.getText().toString().trim(); String End = endAddress.getText().toString().trim(); startAddress.setText( End ); endAddress.setText( Start ); }
Address information to geographic information (longitude and latitude)
Geocoder provides an API for the mutual conversion of address information and geographic information for Baidu map
geocoder = new Geocoder( SelectNodeActivity.this );
The Address information entered by the user is converted by getFromLocationName() method and an Address object is returned; It should be noted that the Address information entered should be more accurate, such as xxx land, xxx District, xxx city, xxx Province, so that the accuracy of the converted geographic information will not shift too much
private String GetNodeValue(String Address){ builder = new StringBuilder( ); try { List<android.location.Address> addresses = geocoder.getFromLocationName(Address,1 ); double start_latitude = addresses.get( 0 ).getLatitude();//latitude double start_longitude = addresses.get( 0 ).getLongitude();//longitude 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(); }
Save geographic information
Save the converted geographic information (latitude and longitude) by using a simple factory singleton class
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 sets the latitude and longitude of the starting point if (!TextUtils.isEmpty(start)) { BNDemoFactory.getInstance().setStartNode(this, start); Log.d( "start:",start ); } //TODO sets the latitude and longitude of the end point if (!TextUtils.isEmpty(end)) { BNDemoFactory.getInstance().setEndNode(this, end); Log.d( "end:",end ); } } }
Routing navigation
private void routePlanToNavi(final Bundle bundle) { List<BNRoutePlanNode> list = new ArrayList<>(); //TODO obtains the longitude and latitude in the main function and starts the route calculation and navigation list.add(BNDemoFactory.getInstance().getStartNode(this)); list.add(BNDemoFactory.getInstance().getEndNode(this)); // Turn off the electronic dog if (BaiduNaviManagerFactory.getCruiserManager().isCruiserStarted()) { BaiduNaviManagerFactory.getCruiserManager().stopCruise(); } BaiduNaviManagerFactory.getRoutePlanManager().routePlanToNavi( list, IBNRoutePlanManager.RoutePlanPreference.ROUTE_PLAN_PREFERENCE_DEFAULT, bundle, handler); }
Node computing requires a lot of memory space and time, so the use of asynchronous communication does not affect the distribution of the main thread and the refresh of the UI
private Handler handler = new Handler( Looper.getMainLooper()) { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_START: Toast.makeText(SelectNodeActivity.this, "Start of road calculation", Toast.LENGTH_SHORT).show(); ControlBoardWindow.getInstance().showControl("Start of road calculation"); break; case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_SUCCESS: Toast.makeText(SelectNodeActivity.this, "Successful routing", Toast.LENGTH_SHORT).show(); ControlBoardWindow.getInstance().showControl("Calculate the road successfully"); // Avoid restricted messages 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("Routing failure"); Toast.makeText(SelectNodeActivity.this.getApplicationContext(), "Routing failure", Toast.LENGTH_SHORT).show(); break; case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_TO_NAVI: Toast.makeText(SelectNodeActivity.this.getApplicationContext(), "Calculate the route successfully and prepare to enter the navigation", Toast.LENGTH_SHORT).show(); ControlBoardWindow.getInstance().showControl("Calculate the route successfully and prepare to enter the navigation"); 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; } } };
Destroy
After using, you should put the destructable contents into onDestroy to avoid the waste of memory space
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mReceiver); stopService(new Intent(this, ForegroundService.class)); }