'How to move Google Map marker automatically as driver is moving

I'm trying to figure out how we can track driver position on Google map as he is moving.

Here's my code:

public class TrackDriverActivity extends AppCompatActivity implements OnMapReadyCallback {

    GoogleMap mGoogleMap;
    LatLng myPos, driverPos;
    MarkerOptions myMarker, driverMarker;
    Polyline directionLine;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track_rongsok_pickup);


        // both LatLng (ours and driver) are initially hardcoded, for testing purpose
        myPos = new LatLng(-6.25, 106.83);
        driverPos = new LatLng(-6.27, 106.81);

        myMarker = new MarkerOptions().position(myPos).title("You");
        driverMarker = new MarkerOptions().position(driverPos).title("Driver");

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map_track_driver);

        mapFragment.getMapAsync(this);


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        super.onStart();
        LocalBroadcastManager.getInstance(this).registerReceiver(driverPositionReceiver, new IntentFilter("DriverPosition"));
    }

    @Override
    protected void onStop() {
        super.onStop();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(driverPositionReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
    }

    // Every 5 seconds, driver broadcasts his current position to us via FCM
    private BroadcastReceiver driverPositionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            DecimalFormat df = new DecimalFormat("0.00");
            double driverLat = Double.parseDouble(intent.getStringExtra("driver_lat"));
            double driverLon = Double.parseDouble(intent.getStringExtra("driver_lon"));
            
            Log.i("NEW_DRIVER_POSITION", "("+driverLat+","+driverLon+")");

            new Thread()
            {
                public void run()
                {
                    TrackDriverActivity.this.runOnUiThread(new Runnable()
                    {
                        public void run()
                        {
                            driverPos = new LatLng(driverLat, driverLon);
                            requestRoute();
                        }
                    });
                }
            }.start();
        }
    };

    private void updateLineDestination(String json) {
        Directions directions = new Directions(TrackDriverActivity.this);
        try {
            List<Route> routes = directions.parse(json);

            if (directionLine != null) directionLine.remove();
            if (routes.size() > 0) {
                directionLine = mGoogleMap.addPolyline((new PolylineOptions())
                        .addAll(routes.get(0).getOverviewPolyLine())
                        .color(ContextCompat.getColor(TrackRongsokPickupActivity.this, R.color.colorgradient))
                        .width(8));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private okhttp3.Callback updateRouteCallback = new okhttp3.Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()){
                String json = Objects.requireNonNull(response.body()).string();
                long distance = MapDirectionAPI.getDistance(getApplicationContext(), json);

                if (distance >= 0){
                    TrackDriverActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            updateLineDestination(json);
                        }
                    });
                }
            }
        }
    };

    private void requestRoute() {
        if (customerPos != null && merchantPos != null) {
            MapDirectionAPI.getDirection(customerPos, merchantPos).enqueue(updateRouteCallback);
        }
    }

    @Override
    public void onMapReady(GoogleMap gmap) {
        mGoogleMap = gmap;

        mGoogleMap.addMarker(myMarker);
        mGoogleMap.addMarker(driverMarker);
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(driverMarker, 15.0f));

        requestRoute();
    }
}

Directions is our class that implements Directions API (https://developers.google.com/maps/documentation/directions/overview), which do stuffs like decoding polylines into list of LatLng, parsing JSON route format, etc.

MapDirectionAPI is our class which complements Directions, e.g for retrieving the route between 2 LatLngs, geocoding, etc.

When running the code:

  • Both markers are displayed on their initial positions correctly
  • A route line between us and driver is drawn correctly (initial position)
  • As the driver is moving, his location change can be seen in logcat

The problem is his marker is still stuck at the starting position. How to fix this?



Solution 1:[1]

Changing the value of driverPos will NOT move the marker that was created with its previous value. You need to move driverMarker in updateLineDestination. Add

driverMarker.setPosition( driverPos );

after

directionLine = mGoogleMap.addPolyline(...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 KaHa6uc