Android Baidu Map (3): Baidu Map Track and Layer Click Event Processing

Keywords: SDK Mobile Google less

Android Baidu Map (1): Detailed introduction of sdk-type method parameters and positioning principle for Baidu Map positioning
Android Baidu Map (2): Baidu Location and Map Display Location Points

Source address https://github.com/zhuhao Happig/BaiduMapApi

The last article describes how to display location points on a map. This article mainly describes how to draw motion tracks on a map, and how to deal with click events on the map layer.

Many sports app s have the need to draw a runner's trajectory. For example, let's take a look at its rendering.


The trajectory map of the grunt motion


The effect to be achieved in this article
1. After running, draw the whole trajectory statically.
2. Drawing the track dynamically in the running process from time to time


Design sketch


How to achieve:
1. Connect dots to dots and draw line layers on MapView of Baidu Map.
2. Get the location point List < LatLng >: Obtain the location point through Baidu positioning sdk: Location Client class, and draw the locus of outdoor sports, which requires high accuracy of the location point, so we must use the position result of gps positioning type.

//Allow the use of gps positioning
mOption.setOpenGps(true);

For more details on the sdk parameters of Baidu's positioning, please read the first article of Baidu Map (1)

A static drawing of the whole trajectory

1. Drawing Track

//Pseudo-code
public void onCreate(){
  // Map Initialization
  MapView mMapView = (MapView) findViewById(R.id.bmapView);
  BaiduMap mBaiduMap = mMapView.getMap();
  // Open Location Layer
  mBaiduMap.setMyLocationEnabled(true);

  //Obtaining the Location Point after Motion
  coordinateConvert();

  //Set the zoom midpoint LatLng target, and zoom ratio          
  MapStatus.Builder builder = new MapStatus.Builder();
  builder.target(target).zoom(18f);

  //Map Settings Zoom Status
  mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));

  /**
  * Configuration line segment layer parameter class: PolylineOptions
  * ooPolyline.width(13): line width
  * ooPolyline.color(0xAAFF0000): Line color red
  * ooPolyline.points(latLngs): List<LatLng> latLngs Location points, connecting adjacent points and points into a line becomes a trajectory.
  */
  OverlayOptions ooPolyline = new PolylineOptions().width(13).color(0xAAFF0000).points(latLngs);

  //Draw a line layer on the map, mPolyline: line layer
  mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
  mPolyline.setZIndex(3);
}
/**
 * Here is the coordinate set Const. google wgs84 taken from google map, which is acquired after simulated motion.
   So we need to convert it into Baidu coordinates; in fact, we should add the location points returned by the positioning sdk into the location set.
   To locate the sdk, you need to set the return coordinate to Baidu coordinate: mOption.setCoorType("bd09ll"), so that it can be used directly without conversion.
 */
private void  coordinateConvert(){
  //Baidu Coordinate Converter Tool Class 
  CoordinateConverter converter  = new CoordinateConverter(); 

  /**
  * Set the coordinate type to be transformed
    CoordType.COMMON: google The coordinates used in maps, Tencent maps and Gaode maps
    CoordType.GPS: Raw GPS coordinates acquired by equipment
  */
  converter.from(CoordType.COMMON);

  double lanSum = 0;
  double lonSum = 0;
  for (int i = 0; i < Const.googleWGS84.length; i++) {
    //"39.881970,116.456218"
    String[] ll = Const.googleWGS84[i].split(",");
    LatLng sourceLatLng = new LatLng(Double.valueOf(ll[0]), Double.valueOf(ll[1]));
    converter.coord(sourceLatLng);  //Coordinate points to be transformed
    LatLng desLatLng = converter.convert();  //Convert to Baidu coordinate point
    latLngs.add(desLatLng);//Join the set of locating points
    lanSum += desLatLng.latitude;
    lonSum += desLatLng.longitude;
  }

  //Here I set the zoom center of the map as all the geometric centers.
  target = new LatLng(lanSum/latLngs.size(), lonSum/latLngs.size());
}

Motion Trajectory Effect


Trajectory diagram


2. Add Start Icon Layer, Click Layer to Response to Events

//Start Layer Icon
BitmapDescriptor startBD= BitmapDescriptorFactory
            .fromResource(R.drawable.ic_me_history_startpoint);
//Endpoint Layer Icon
BitmapDescriptor finishBD= BitmapDescriptorFactory
            .fromResource(R.drawable.ic_me_history_finishpoint);

//Display information window in map
InfoWindow mInfoWindow;

MarkerOptions oStart = new MarkerOptions();//Layer Parameter Configuration Class of Map Markup Type 
oStart.position(latLngs.get(0));//Layer position point, the first point is the starting point
oStart.icon(startBD);//Setting Layer Pictures
oStart.zIndex(1);//Setting Layer Index
//Add Starting Layer
Marker mMarkerA = (Marker) (mBaiduMap.addOverlay(oStart)); 

//Add Endpoint Layer
MarkerOptions oFinish = new MarkerOptions().position(latLngs.get(latLngs.size()-1)).icon(finishBD).zIndex(2);
Marker mMarkerB = (Marker) (mBaiduMap.addOverlay(oFinish));

//Setting Layer Click to Listen for Callbacks
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {
  public boolean onMarkerClick(final Marker marker) {
    if (marker.getZIndex() == mMarkerA.getZIndex() ) {//If it is the starting point layer
      TextView textView = new TextView(getApplicationContext());
      textView.setText("Starting point");
      textView.setTextColor(Color.BLACK);
      textView.setGravity(Gravity.CENTER);
      textView.setBackgroundResource(R.drawable.popup);

      //Setting Information Window Click Callback
      OnInfoWindowClickListener listener = new OnInfoWindowClickListener() {
        public void onInfoWindowClick() {
          //Here is the main thread, which can realize some of its own functions.
          Toast.makeText(getApplicationContext(),"Here is the starting point.", Toast.LENGTH_SHORT).show();
          mBaiduMap.hideInfoWindow();//Hidden Information Window
        }
      };

      LatLng latLng = marker.getPosition();//Location Points Displayed in Information Window

      /**
      * Construct an InfoWindow by passing in bitmap descriptor
      * bd - Display bitmap
        position - InfoWindow Displayed position points
        yOffset - The information window will overlap with the layer icon. Setting the offset of Y axis can solve this problem.
        listener - Click on the listener
      */
      mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(textView), latLng, -47, listener);
      mBaiduMap.showInfoWindow(mInfoWindow);//Display information window
    } else if (marker.getZIndex() == mMarkerB.getZIndex()) {//If it's the endpoint layer
      Button button = new Button(getApplicationContext());
      button.setText("End");
      button.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
          Toast.makeText(getApplicationContext(),"This is the end point.", Toast.LENGTH_SHORT).show();
          mBaiduMap.hideInfoWindow();
        }
      });

      LatLng latLng = marker.getPosition();
      /**
      * An InfoWindow is constructed from the incoming view, which is used only to generate a Bitmap to plot on the map, and the listening event is implemented by itself.
        view - view on display
        position - Displayed geographic location
        yOffset - Y Axis offset
      */
      mInfoWindow = new InfoWindow(button, latLng, -47);
      mBaiduMap.showInfoWindow(mInfoWindow);
    } 
    return true;
 }
});

//You can also add click events to the trajectory
mBaiduMap.setOnPolylineClickListener(new BaiduMap.OnPolylineClickListener() {
  @Override
  public boolean onPolylineClick(Polyline polyline) {
    if (polyline.getZIndex() == mPolyline.getZIndex()) {
      Toast.makeText(getApplicationContext(),"Point:" + polyline.getPoints().size() + ",width:" + polyline.getWidth(), Toast.LENGTH_SHORT).show();
    }
    return false;
  }
});

Motion track effect, click icon to pop up information window


Click on the start Icon


Click on the icon to pop up the information window to pop up Toast


Pop-up Toast


At this point, the whole trajectory is drawn and the click event is added to the layer after the exercise.

Dynamically Drawing Motion Trajectories in Two Times

Time-to-time Dynamic Track Drawing Effect


Location and direction of arrow


The key lies in the point selection: the accuracy of some points returned by the gps just after receiving the signal is not high, which is easy to cause position offset. How to pick the point is very important.

//Pseudo-code
public void onCreate() {
  mMapView = (MapView) findViewById(R.id.bmapView);
  mBaiduMap = mMapView.getMap();
  // Open Location Layer
  mBaiduMap.setMyLocationEnabled(true);

  /**Add map zoom state change monitoring, when manually zooming in or out of the map, get the scaled proportion, and then get the next location.
  *  Reset the zoom scale for the map, otherwise the map will revert to the default mCurrentZoom zoom scale
  */
  mCurrentZoom = 18;
  mBaiduMap.setOnMapStatusChangeListener(new OnMapStatusChangeListener() {
    @Override
    public void onMapStatusChangeStart(MapStatus arg0) {
    }

    @Override
    public void onMapStatusChangeFinish(MapStatus arg0) {
      mCurrentZoom = arg0.zoom;//Get the value of the finger after zooming in the map
    }

    @Override
    public void onMapStatusChange(MapStatus arg0) {
    }
  });

  //Set the location icon type to follow mode
  mBaiduMap.setMyLocationConfiguration(new MyLocationConfiguration(
                com.baidu.mapapi.map.MyLocationConfiguration.LocationMode.FOLLOWING, true, null));

  // Location initialization
  mLocClient = new LocationClient(this);
  mLocClient.registerLocationListener(myListener);
  LocationClientOption option = new LocationClientOption();
  option.setLocationMode(LocationMode.Device_Sensors);//Accept only gps location
  option.setOpenGps(true); // Allowing gps positioning
  option.setCoorType("bd09ll"); // Setting coordinate type
  option.setScanSpan(1000);//One gps per second
  mLocClient.setLocOption(option);
}

//Start to get the location point
public void onStart() {
  start.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        if (mLocClient != null && !mLocClient.isStarted()) {
            mLocClient.start();
        }
    }
  });
}

//Location callback is very important
public class MyLocationListenner implements BDLocationListener {

    @Override
    public void onReceiveLocation(final BDLocation location) {

        if (location == null || mMapView == null) {
            return;
        }

        if (location.getLocType() == BDLocation.TypeGpsLocation) {//As long as the gps point

            if (isFirstLoc) {//First positioning
                /**The first point is very important, which determines the effect of the trajectory. The accuracy of some points returned by the gps just after receiving the signal is not high.
                * Choose a starting point with relatively high accuracy as far as possible. This process can be completed in about 5-10 seconds after receiving the signal from the gps, without affecting the effect.
                * Note: gps receives satellite signals in less than ten seconds and more than a few minutes.
                * If the mobile phone can not receive the gps for a long time, quit, restart the mobile phone and try again, this is the hardware reason.
                */
                LatLng ll = null;

                //Choose a starting point with relatively high accuracy
                ll = getMostAccuracyLocation(location);
                if(ll == null){
                    return;
                }
                isFirstLoc = false;
                points.add(ll);//Join the collection
                last = ll;

                //Display the current location point and zoom the map
                locateAndZoom(location, ll);

                //Mark the Start Layer Location
                MarkerOptions oStart = new MarkerOptions();// Map Marker Cover Parameter Configuration Class
                oStart.position(points.get(0));// Cover location point, the first point is the starting point
                oStart.icon(startBD);// Setting Cover Pictures
                mBaiduMap.addOverlay(oStart); // Add this layer to the map
                return;//Draw a trajectory with at least two points, and you can return from the first location.
            }

            //Start with the second point
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
            //The frequency of sdk callback to gps position is 1 second, and the dynamic drawing of position points is not very obvious. It can be set that the distance between points is more than 5 meters before adding to the set.
            if (DistanceUtil.getDistance(last, ll) < 5) {
                return;
            }

            points.add(ll);//If you want to draw the whole trajectory after the motion is completed, the position points are in this set.

            last = ll;

            //Display the current location point and zoom the map
            locateAndZoom(location, ll);

            //Clear the last trajectory to avoid overlapping paintings
            mMapView.getMap().clear();

            //Starting point layers will also be cleared and redrawn
            MarkerOptions oStart = new MarkerOptions();
            oStart.position(points.get(0));
            oStart.icon(startBD);
            mBaiduMap.addOverlay(oStart);

            //Draw a trajectory line layer of points in the points set and display it on the map
            OverlayOptions ooPolyline = new PolylineOptions().width(13).color(0xAAFF0000).points(points);
            mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
        }
    }
}

//First positioning is very important. Choose a starting point with relatively high accuracy.
private LatLng getMostAccuracyLocation(final BDLocation location){

    if (location.getRadius()>25) {//Direct abandonment of points with position accuracy greater than 25 meters
        return null;
    }

    LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());

    if (DistanceUtil.getDistance(last, ll ) > 5) {
        last = ll;
        points.clear();//There are two points greater than 5, come back.
        return null;
    }
    points.add(ll);
    last = ll;
    //The distance between five consecutive points is less than 5. It is considered that the gps is stable and the latest point is the starting point.
    if(points.size() >= 5){
        points.clear();
        return ll;
    }
    return null;
}

//Display the current location point and zoom the map
private void locateAndZoom(BDLocation location, LatLng ll) {
    /**
    * Record the current latitude and longitude. When the position is unchanged, the mobile phone rotates to get the direction of the direction sensor.
      Reset the location parameters of the map to make the map arrow rotate with the mobile phone in the following mode
    */
    mCurrentLat = location.getLatitude();
    mCurrentLon = location.getLongitude();
    locData = new MyLocationData.Builder().accuracy(0)//Remove the precision circle
            //This mCurrentDirection obtains the orientation information of the mobile phone sensor for itself, clockwise 0-360
            .direction(mCurrentDirection).latitude(location.getLatitude())
            .longitude(location.getLongitude()).build();
    mBaiduMap.setMyLocationData(locData);//Display the current location point

    //Set zoom centers and zoom scale values for maps
    builder = new MapStatus.Builder();
    builder.target(ll).zoom(mCurrentZoom);
    mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
}

//End of Exercise Add End Icon
finish.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {

        if (mLocClient != null && mLocClient.isStarted()) {
            mLocClient.stop();//Stop positioning

            if(points.size() <= 0){
                return;
            }

            //Remember to mark the end point icon at the end of the exercise
            MarkerOptions oFinish = new MarkerOptions();
            oFinish.position(points.get(points.size() - 1));
            oFinish.icon(finishBD);
            mBaiduMap.addOverlay(oFinish); 
        }
    }
});

Exit and Release Resources

//Pseudo-code
protected void onDestroy() {
  // Destruction Location at Exit
  mLocClient.unRegisterLocationListener(myListener);
  mLocClient.stop();
  // Close the Location Layer
  mBaiduMap.setMyLocationEnabled(false);
  mMapView.getMap().clear();
  mMapView.onDestroy();
  mMapView = null;
  startBD.recycle();
  finishBD.recycle();
}

Note: When we draw the motion trajectory, we need to locate the position returned by the sdk with high accuracy, so the effect of the trajectory will be better. Therefore, we must accept the position points of the gps. But the accuracy of the position of the GPS is not high when the signal is received at the beginning, and the position drift will occur, so we need to select a point with better accuracy. In buildings, bridges, trees and tunnels, the GPS signal is not good and the accuracy is not high, so in the open area, the trajectory effect is better.

For more details on Baidu Map and Location sdk parameters, please read the first and second articles of Baidu Map.

The above article is a summary of my work for your reference. Please correct any mistakes.

Posted by bretx on Mon, 17 Jun 2019 13:15:30 -0700