Refresh many Google Map markers position, without refresh the whole map in Android

QuentR picture QuentR · Mar 7, 2015 · Viewed 8.4k times · Source

I'm currently developing an Android app that have to receive GPS positions from other devices every minutes, and display them on a map. I'm using the GoogleMaps Api V2,

What i'd like to do, is to refresh the position marker very time a new position is received. (I don't want to refresh the whole map)

For the moment, I've added a button in the menu that enables me to refresh the entire map.

To detail to structure, I have a service that run MQTT, and every time a position is received, I add it into an Hashmap, that represents my map data source. This HashMap is a Singleton that extends Observable. Moreover, my fragment that display the my implements Observer.

Code from my Fragment that implements Observer

 public void update(Observable observable, final Object object)
 {

     if (observable instanceof ListPositions && object != null)
     {        
         Position p = (Position) object;
         LatLng position = new LatLng(p.getLatitude(), p.getLongitude());
         // Where i'd like to move the markers

     }
     else
     {
        // Where i'd like to remove the marker from the map
     }
 }

Code From my Singleton List of position

public class ListPositions extends Observable{

private HashMap<String,Position> mapPosition;

private ListPositions()
{
    mapPosition = new HashMap<String, Position>();
    VehicleMapFragment mapFragmentObserver = new VehicleMapFragment();
    this.addObserver(mapFragmentObserver);
}


private static ListPositions INSTANCE = null;


public static synchronized ListPositions getInstance()
{
    if (INSTANCE == null)
    { INSTANCE = new ListPositions();
    }
    return INSTANCE;
}

public int getNumberOfPosition()
{
    return mapPosition.size();
}

public void addPosition(String key, Position p){
    mapPosition.put(key,p);
    setChanged();
    notifyObservers(p);
}

public void removePosition(String key){
    mapPosition.remove(key);
    setChanged();
    notifyObservers();
}

Code From myService that runs MQTT

public void onPositionMessageReceived(MqttMessage message, String source)
 {
    Gson gson = new Gson();
    String s = gson.toJson(message.toString());
    String jsonPosition = gson.toJson(message.toString());
    jsonPosition = formatMessage(jsonPosition);
    Position p = gson.fromJson(jsonPosition, Position.class);

    ListPositions.getInstance().addPosition(source, p);


}

Can someone know how to move each markers individually without refreshing the whole map, in my update function from my Observer Fragment? May I use a Handler to update the Map, from an other thread to modify the Main UI Thread ?

Many thanks

EDIT :

Because the first methode given by AniV didn't work for me, I've tried with an Asyntask that runs when my Observer get a notification from the Observable List.

Code from the Observer Fragment :

public void update(Observable observable, final Object object)
{
    if (observable instanceof ListPositions && object != null)
    {
        Position p = (Position) object;

        position = new LatLng(p.getLatitude(), p.getLongitude());
        options = new MarkerOptions().position(position).title("TEST").snippet("TEST");

        PositionUpdate positionUpdaterTask = new PositionUpdate(myGoogleMap, options, position);
    positionUpdaterTask.execute();
    }
}

Code from the AsyncTask :

public class PositionUpdate extends AsyncTask<Void, Void, Void>{

private GoogleMap myGoogleMap;
private MarkerOptions options;
private LatLng positionToAdd;


public PositionUpdate(GoogleMap googleMap, MarkerOptions options, LatLng position)
{
    this.myGoogleMap = googleMap;
    this.options = options;
    this.positionToAdd = position;
}


@Override
protected Void doInBackground(Void...voids)
{
    return null;
}

@Override
protected void onPostExecute(Void aVoid)
{
    if (myGoogleMap != null)
    {
        myGoogleMap.addMarker(options.position(positionToAdd));
        Log.i(ConstElisa.LOG_ELISA, "MARKER ADDED");
    }
    else
    {
        Log.e(ConstElisa.LOG_ELISA, "ERROR ADDING THE MARKER");
    }

    super.onPostExecute(aVoid);
}

However, in this case, myGoogleMap variable is always null, so the marker is never added to the Google Map.

Does someone have an idea why this variable is null ?

Answer

QuentR picture QuentR · Mar 11, 2015

I finally succeeded in doing that thing by using the AsyncTask.

In my EDIT, I said that I had some trouble with the null instance of my Google Maps object. This was caused by my Singleton Observable. Indeed, in the constructor, I used

VehicleMapFragment mapFragmentObserver = new VehicleMapFragment();
this.addObserver(mapFragmentObserver); 

This code sample recreated another instance of my Fragment, and that the reason why ii had Null objects.

To correct this problem, I simply used :

ListPositions.getInstance().addObserver(this);

in my Fragment Observer.

So if you want to update a marker position without refreshing the whole map, you can use the Observer/Observable Pattern, and use an Asynctask to update the marker position.