I am making a GPS tracker using google maps API and displaying the users current position on a map using ItemizedOverylay. As the users position changes regularly, I've set up a CountDownTimer to delete the current Itemizedoverlay and add a new one at the new position every 5 seconds (there is no way of changing an itemizedOverlay's position) but the screen isn't drawing the new positions unless i physically touch the screen! Here is the code for my itemized overlay:
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.Toast;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.OverlayItem;
public class HelloItemizedOverlay extends ItemizedOverlay{
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
Context mContext;
public HelloItemizedOverlay(Drawable defaultMarker) {
/*This passes the defaultMarker up to the default constructor
* to bound its coordinates and then initialize mContext with the given Context.*/
super(boundCenterBottom(defaultMarker));
}
public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
/*This passes the defaultMarker up to the default constructor
* to bound its coordinates and then initialize mContext with the given Context.*/
super(boundCenterBottom(defaultMarker));
mContext = context;
}
@Override
protected boolean onTap(int index) {
/*This uses the member android.content.Context to create
* a new AlertDialog.Builder and uses the tapped OverlayItem's title
* and snippet for the dialog's title and message text. (You'll see the
* OverlayItem title and snippet defined when you create it below.)*/
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
/*Each time you add a new OverlayItem to the ArrayList, you must
* call populate() for the ItemizedOverlay, which will read each
* of the OverlayItems and prepare them to be drawn.*/
populate();
}
public void addOverlayList(List<OverlayItem> overlayitems) {
Object temp[] = overlayitems.toArray();
try{
for(int i = 0;i<temp.length;i++)
{
mOverlays.add((OverlayItem)temp[i]);
}
}catch(Error e)
{
Toast.makeText(mContext, "Something happened when adding the overlays:"+e.getMessage() ,
Toast.LENGTH_LONG).show();
}
populate();
}
public void removeOverlayList(List<OverlayItem> overlayitems) {
Object temp[] = overlayitems.toArray();
try{
for(int i = 0;i<temp.length;i++)
{
mOverlays.remove((OverlayItem)temp[i]);
}
}catch(Error e)
{
Toast.makeText(mContext, "Something happened when adding the overlays:"+e.getMessage() ,
Toast.LENGTH_LONG).show();
}
populate();
}
public void removeOverlay(OverlayItem overlay){
mOverlays.remove(overlay);
populate();
}
public void doPopulate()
{
populate();
}
@Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return mOverlays.get(i);
}
@Override
public int size() {
/*You must also override the size() method to return the current
* number of items in the ArrayList:*/
return mOverlays.size();
}
}
Does anyone know if there is a method or something I can call to force a redraw/refresh when I put the new items in?
EDIT: Here is a snippet of the MapsActivity:
public class HelloGoogleMaps extends MapActivity {
/***************************
* map stuff
*****/
HelloItemizedOverlay myPosition;
MapView mapView;
MapController mapController;
List<Overlay> mapOverlays;
OverlayItem myPositionOverlayItem;
public double myLatitude = 0;
public double myLongitude = 0;
public double myCoarseLatitude = 0;
public double myCoarseLongitude = 0;
public boolean isGPS;
public boolean isGPSFix;
public boolean useGPSLocation;
public boolean useNetworkLocation;
public long mLastLocationMillis;//system time of last gps contact
/*boolean so when gps gets your location it will zoom to where you are,
* but will only do this once (once it's set to true)*/
boolean pickedUpLocation;
public MyCount counter;//for timing events
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mymapview);
pickedUpLocation = false;
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setStreetView(true);
/*mapcontroller controls zoom etc*/
mapController = mapView.getController();
mapOverlays = mapView.getOverlays();
Drawable my_icon = this.getResources().getDrawable(R.drawable.androidmarker_teacher);
myPosition = new HelloItemizedOverlay(my_icon, this);
itemizedoverlay = new HelloItemizedOverlay(drawable, this);
/*All overlay elements on a map are held by the MapView, so when you
* want to add some, you have to get a list from the getOverlays() method.
* Then instantiate the Drawable used for the map marker, which was saved in
* the res/drawable/ directory. The constructor for HelloItemizedOverlay
* (your custom ItemizedOverlay) takes the Drawable in order to set the
* default marker for all overlay items.*/
/*Initialise GPS*/
try{
LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListener = new MyLocationListener();
//get fine location
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
//get coarse location
mlocManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 0, 0, mlocListener);
boolean isGPS = mlocManager.isProviderEnabled (LocationManager.GPS_PROVIDER);
MyGPSListener myGPSListener = new MyGPSListener();
mlocManager.addGpsStatusListener(myGPSListener);
}
catch(Error e)
{
Toast.makeText( getApplicationContext(),"Error!"+e.getMessage(),Toast.LENGTH_SHORT).show();
}
GeoPoint point = new GeoPoint((int)(myCoarseLatitude * 1e6),(int) (myCoarseLongitude* 1e6));
myPositionOverlayItem = new OverlayItem(point, "Evening guvna!", "This is where i am");
/*All that's left is to add this OverlayItem to your collection in the
* HelloItemizedOverlay instance, then add the HelloItemizedOverlay to the MapView: */
myPosition.addOverlay(myPositionOverlayItem);
mapOverlays.add(myPosition);
/*begin counting 5 seconds to update positions*/
counter = new MyCount(5000,1000);
counter.start();
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
public void updateMyPosition()
{
/*remove my guy*/
mapView.getOverlays().remove(myPosition);
myPosition.removeOverlay(myPositionOverlayItem);
myPosition.doPopulate();
GeoPoint point;
if(useGPSLocation)
{
point = new GeoPoint((int)(myLatitude * 1e6),(int) (myLongitude* 1e6));
}
else
{
point = new GeoPoint((int)(myCoarseLatitude * 1e6),(int) (myCoarseLongitude* 1e6));
}
myPositionOverlayItem = new OverlayItem(point, "You are here", "Awww yeah!");
myPosition.addOverlay(myPositionOverlayItem);
myPosition.doPopulate();
mapOverlays.add(myPosition);
}
public void clearTheMap()
{
mapView.getOverlays().clear();
myPosition.doPopulate();
}
/*******************************************************
* GPS!!!!!!!!
* This method gets the location of you from gps
* ************************************************/
public class MyLocationListener implements LocationListener
{
public void onLocationChanged(Location loc)
{
String provider = loc.getProvider();
if(provider.equals(LocationManager.GPS_PROVIDER))
{
myLatitude = loc.getLatitude();
myLongitude = loc.getLongitude();
mLastLocationMillis = SystemClock.elapsedRealtime();
if((!pickedUpLocation)&&(myLatitude!=0))
{
mapController.animateTo(new GeoPoint((int)(myLatitude * 1e6),(int) (myLongitude* 1e6)));
pickedUpLocation = true;
}
}
else
{
myCoarseLatitude = loc.getLatitude();
myCoarseLongitude = loc.getLongitude();
if((!pickedUpLocation)&&(myCoarseLatitude!=0))
{
//Toast.makeText(getBaseContext(), "picked up Location with network - "+myCoarseLatitude+" "+myCoarseLongitude, Toast.LENGTH_LONG).show();
mapController.animateTo(new GeoPoint((int)(myCoarseLatitude * 1e6),(int) (myCoarseLongitude* 1e6)));
pickedUpLocation = true;
}
}
/*first time it picks up your location it will animate to where you are*/
/*
String Text = "My current location is: "+
"Latitud = " + loc.getLatitude()+
"Longitud = " + loc.getLongitude();
Toast.makeText( getApplicationContext(),Text,Toast.LENGTH_SHORT).show();
*/
}
public void onProviderDisabled(String provider)
{
Toast.makeText( getApplicationContext(),"Gps Disabled",Toast.LENGTH_SHORT ).show();
myLatitude = -1;
myLongitude = -1;
}
public void onProviderEnabled(String provider)
{
Toast.makeText( getApplicationContext(),"Gps Enabled",Toast.LENGTH_SHORT).show();
myLatitude = 0;
myLongitude = 0;
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
/***********************************************
* -GPS Status monitor-
* Will see if the sattelites are still fixed to your phone
* If satellites arent available, it takes network (coarse) location
* If a fix is aquired it will use GPS (fine) location
* **********************************/
private class MyGPSListener implements GpsStatus.Listener {
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
if (myLatitude != 0)
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
if (isGPSFix) { // A fix has been acquired.
useGPSLocation = true;
useNetworkLocation = false;
} else { // The fix has been lost.
useGPSLocation = false;
useNetworkLocation = true;
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
// Do something.
isGPSFix = true;
useGPSLocation = true;
useNetworkLocation = false;
break;
}
}
}
/*************************************************************
* Counter class for timing events
**********/
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onFinish() {
clearTheMap();
updateMyPosition();//redraw my guy
myPosition.doPopulate();
//Toast.makeText( getApplicationContext(),"Sent my position - used ",Toast.LENGTH_SHORT).show();
resetTimer();
}
public void resetTimer()
{
counter = new MyCount(5000,1000);
counter.start();
}
@Override
public void onTick(long millisUntilFinished) {
/*tv.setText(”Left: ” + millisUntilFinished/1000);*/
}
}
}
Use mapview.invalidate()
. This will eventually cause a redraw.