Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
275 views
in Technique[技术] by (71.8m points)

java - Location Updates every 35 seconds and draw a circle on the current location

Currently I am drawing a Circle on my Current Location after every 35 seconds of the location changed and 10 meters of distance moved.

So I have implemented this feature under LocationChanged as soon as the location gets changed(35 seconds and 10 meters moved), I am drawing a Circle on the Google Maps on the Current Location.

Problem Statement:-

My App is running very slow. Sometimes my app gets hanged?. May be because my code is not that efficient with the way I have wrote below?

Basically, I just need to draw a Circle on my current location after every 35 seconds and 10 meters distance moved.

Is there any problem with my code? Any thoughts like how should I improve this more, to run it smoothly.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);    

    locationListener = new GPSLocationListener();

    locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 
            35000, 
            10, 
            locationListener);

    mapView = (MapView) findViewById(R.id.mapView);
    listView = (ListView) findViewById(R.id.mylist);
    mapView.setStreetView(true);
    mapView.setBuiltInZoomControls(true);
    mapController = mapView.getController();
    mapController.setZoom(15);
}

private class GPSLocationListener implements LocationListener {
    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            GeoPoint point = new GeoPoint(
                    (int) (location.getLatitude() * 1E6), 
                    (int) (location.getLongitude() * 1E6));

            findUsersInCurrentRadius(4,location.getLatitude(),location.getLongitude());

            mapController.animateTo(point);
            mapController.setZoom(15);

            // add marker
            MapOverlay mapOverlay = new MapOverlay(this,android.R.drawable.star_on);
            mapOverlay.setPointToDraw(point);
            List<Overlay> listOfOverlays = mapView.getOverlays();
            listOfOverlays.clear();
            listOfOverlays.add(mapOverlay);

            String address = ConvertPointToLocation(point);
            Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();

            mapView.invalidate();
        }
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }
}

This is my MapOverlay class in which I am drawing a Circle.

class MapOverlay extends Overlay {
    private GeoPoint pointToDraw;
    int[] imageNames=new int[6];

    public MapOverlay(GPSLocationListener gpsLocationListener, int currentUser) {
        imageNames[0]=currentUser;
    }

    public void setPointToDraw(GeoPoint point) {
        pointToDraw = point;
    }

    public GeoPoint getPointToDraw() {
        return pointToDraw;
    }

    @Override
    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
        super.draw(canvas, mapView, shadow);
        //---translate the GeoPoint to screen pixels---
        Point screenPts = new Point();
        mapView.getProjection().toPixels(pointToDraw, screenPts);
        //--------------draw circle----------------------
        Point pt = mapView.getProjection().toPixels(pointToDraw,screenPts);
        Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setColor(0x30000000);
        circlePaint.setStyle(Style.FILL_AND_STROKE);

        int totalCircle=4;
        int radius=40;
        int centerimagesize=35;

        for (int i = 1; i <= totalCircle; i ++) { 
            canvas.drawCircle(screenPts.x,screenPts.y, i*radius, circlePaint); 
        } 

        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),imageNames[0]), (screenPts.x-(centerimagesize/2)),(screenPts.y-(centerimagesize/2)), null);

        super.draw(canvas,mapView,shadow);

        return true;
    }


}

Updated Code:-

private MapView mapView;
private ListView listView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mapView = (MapView) findViewById(R.id.mapView);
    listView = (ListView) findViewById(R.id.mylist);

    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);    

    locationListener = new GPSLocationListener(mapView);

    locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 
            35000, 
            0, 
            locationListener);


    mapView.setStreetView(true);
    mapView.setBuiltInZoomControls(true);
    mapController = mapView.getController();
    mapController.setZoom(15);
}


    private class GPSLocationListener implements LocationListener {

    MapOverlay mapOverlay;

    public GPSLocationListener(MapView mapView) {
        mapOverlay = new MapOverlay(this,android.R.drawable.star_on);
        List<Overlay> listOfOverlays = mapView.getOverlays();
        listOfOverlays.add(mapOverlay);
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            GeoPoint point = new GeoPoint(
                    (int) (location.getLatitude() * 1E6), 
                    (int) (location.getLongitude() * 1E6));

            mapController.animateTo(point);
            mapController.setZoom(15);

            // **See no need to make a new Object here**
            mapOverlay.setPointToDraw(point);
            mapView.invalidate();
        }
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }
}


    class MapOverlay extends Overlay {
    private GeoPoint pointToDraw;
    int[] imageNames=new int[6];
    private Point mScreenPoints;
    private Bitmap mBitmap;
    private Paint mCirclePaint;


    public MapOverlay(GPSLocationListener gpsLocationListener, int currentUser) {
        imageNames[0]=currentUser;
        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setColor(0x30000000);
        mCirclePaint.setStyle(Style.FILL_AND_STROKE);
        mBitmap = BitmapFactory.decodeResource(getResources(),imageNames[0]);
        mScreenPoints = new Point();
    }

    public void setPointToDraw(GeoPoint point) {
        pointToDraw = point;
    }

    public GeoPoint getPointToDraw() {
        return pointToDraw;
    }

    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
        super.draw(canvas, mapView, shadow);
        mScreenPoints = mapView.getProjection().toPixels(pointToDraw, mScreenPoints);

        int totalCircle=4;
        int radius=40;
        int centerimagesize=35;

        for (int i = 1; i <= totalCircle; i ++) { 
            canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, i*radius, mCirclePaint); 
        } 

        canvas.drawBitmap(mBitmap, (mScreenPoints.x-(centerimagesize/2)),(mScreenPoints.y-(centerimagesize/2)), null);
        super.draw(canvas,mapView,shadow);

        return true;
    }


} 
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Here is a few things to remember when drawing:

  1. Do not block the Main UI Thread
  2. Remember Recycle objects.
  3. Remember Recycle objects.
  4. And always Remember to Recycle Objects.

Possible UI Thread Blockage

This code looks like it is calling a potentially expensive action on the callback of onLocationChanged() which is really dangerous to do because you could end up in an ANR. This should probably be done on a background AsyncTask and then the toast shown on the result of it.

String address = ConvertPointToLocation(point);
Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();

Better Management of Resources on Maps

Instead of adding a new overlay each time, make sure to recycle the instance and just reset it's position.

private class GPSLocationListener implements LocationListener {
    MapOverlay mOverlay;

    public GPSLocationListener() {

    }

   @Override
   public void onLocationChanged(Location location) {
    if (location != null) {
        GeoPoint point = new GeoPoint(
                (int) (location.getLatitude() * 1E6), 
                (int) (location.getLongitude() * 1E6));

        findUsersInCurrentRadius(4,location.getLatitude(),location.getLongitude());

        mapController.animateTo(point);
        mapController.setZoom(15);

        if (mOverlay == null) {
            // Add this marker to the list of overlays always.
            // This stuff never changes so there is no need to do this logic
            // Every 30 secs. Loading images is **Expensive**
            mOverlay = mMapOverlay = new MapOverlay(this,android.R.drawable.star_on);
            List<Overlay> listOfOverlays = mapView.getOverlays();
            listOfOverlays.add(mMapOverlay);
        }
        // **See, no need to make a new Object here**
        mOverlay.setPointToDraw(point);

        // This can probably be done at another time.
        // String address = ConvertPointToLocation(point);
        // Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();

        mapView.invalidate();
    }

This code can reuse this marker and just update it's position. You should only create one if it is not in the list.

Better Drawing

Ok next remember don't create objects in the onDraw() method if you don't have to. Once the marker knows where to draw to, you should have everything cached so that you can just focus on drawing. For Example:

public class MapOverlay {

    private GeoPoint pointToDraw;
    int[] imageNames=new int[6];
    // This is the cached Point on the screen that will get refilled on every draw
    private Point mScreenPoints;
    // This is the cached decoded bitmap that will be drawn each time
    private Bitmap mBitmap;
    // Cached Paint
    private Paint mCirclePaint;

    public MapOverlay(GPSLocationListener gpsLocationListener, int currentUser) {
      imageNames[0]=currentUser;
      // This only needs to be made here, once. It never needs to change.
      mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      mCirclePaint.setColor(0x30000000);
      mCirclePaint.setStyle(Style.FILL_AND_STROKE);
      // We only need to load this image once and then just keep drawing it when dirtyed.
      mBitmap = BitmapFactory.decodeResource(context.getResources(),imageNames[0]);
      // This Point object will be changed every call to toPixels(), but the instance can be recycled
      mScreenPoints = new Point();
    }

    public void setPointToDraw(GeoPoint point) {
      pointToDraw = point;
    }

    public GeoPoint getPointToDraw() {
      return pointToDraw;
    }

    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
      super.draw(canvas, mapView, shadow);
      // In the case where nothing has been set yet, don't do any drawing
      if (pointToDraw == null) {
         return true;
      }
      //--------------draw circle----------------------
      mScreenPoints = mapView.getProjection().toPixels(pointToDraw, mScreenPoints);

      int totalCircle=4;
      int radius=40;
      int centerimagesize=35;

      for (int i = 1; i <= totalCircle; i ++) { 
          canvas.drawCircle(screenPts.x,screenPts.y, i*radius, mCirclePaint); 
      } 

      canvas.drawBitmap(mBitmap, (screenPts.x-(centerimagesize/2)),(screenPts.y-(centerimagesize/2)), null);
      super.draw(canvas,mapView,shadow);

      return true;
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...