位置每35秒更新和绘制圆的当前位置新和、当前位置、位置

2023-09-04 13:13:22 作者:萘安

目前,我画我的当前位置后每35秒的位置改变到10米距离移动。

所以我在 LocationChanged 实现此功能,一旦位置得到改变(35秒10米移动),我画圈上的谷歌地图上的当前位置

问题陈述: -

我的应用程序的运行速度非常慢。有时候,我的应用程序被绞死?可能是因为我的code不是与我已经写了下面的方式有效?

基本上,我只需要每35秒和10米的距离移动后画一个圈对我目前的位置。

有没有用我的code什么问题?怎么样有什么想法,我应该改善这个越多,顺利运行。

  @覆盖
公共无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);

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

    LocationListener的=新GPSLocationListener();

    locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            35000,
            10,
            LocationListener的);

    图形页面=(图形页面)findViewById(R.id.mapView);
    ListView的=(的ListView)findViewById(R.id.mylist);
    mapView.setStreetView(真正的);
    mapView.setBuiltInZoomControls(真正的);
    mapController = mapView.getController();
    mapController.setZoom(15);
}

私有类GPSLocationListener实现LocationListener的{
    @覆盖
    公共无效onLocationChanged(位置定位){
        如果(位置!= NULL){
            的GeoPoint点=新的GeoPoint(
                    (中间体)(location.getLatitude()* 1E6),
                    (中间体)(location.getLongitude()* 1E6));

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

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

            //添加标记
            MapOverlay mapOverlay =新MapOverlay(这一点,android.R.drawable.star_on);
            mapOverlay.setPointToDraw(点);
            名单<覆盖> listOfOverlays =调用MapView.getOverlays();
            listOfOverlays.clear();
            listOfOverlays.add(mapOverlay);

            字符串的地址= ConvertPointToLocation(点);
            Toast.makeText(getBaseContext(),地址,Toast.LENGTH_SHORT).show();

            mapView.invalidate();
        }
    }

    @覆盖
    公共无效onProviderDisabled(字符串提供商){
    }

    @覆盖
    公共无效onProviderEnabled(字符串提供商){
    }

    @覆盖
    公共无效onStatusChanged(字符串商,INT地位,捆绑演员){
    }
}
 

这是我MapOverlay类中,我画一个圈。

 类MapOverlay扩展覆盖{
    私人的GeoPoint pointToDraw;
    INT [] imageNames =新INT [6];

    公共MapOverlay(GPSLocationListener gpsLocationListener,诠释的currentUser){
        imageNames [0] =的currentUser;
    }

    公共无效setPointToDraw(的GeoPoint点){
        pointToDraw =点;
    }

    公众的GeoPoint getPointToDraw(){
        返回pointToDraw;
    }

    @覆盖
    公共布尔平局(画布油画,图形页面图形页面,布尔影子,时长){
        super.draw(帆布,图形页面,阴影);
        // ---翻译的GeoPoint到屏幕像素---
        点screenPts =新的点();
        。MapView.getProjection()在toPixels(pointToDraw,screenPts);
        // --------------平局圈----------------------
        。点PT = MapView.getProjection()在toPixels(pointToDraw,screenPts);
        油漆circlePaint =新的油漆(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setColor(0x30000000);
        circlePaint.setStyle(Style.FILL_AND_STROKE);

        INT totalCircle = 4;
        INT半径= 40;
        INT centerimagesize = 35;

        的for(int i = 1; I< = totalCircle;我++){
            canvas.drawCircle(screenPts.x,screenPts.y,I *半径,circlePaint);
        }

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

        super.draw(帆布,图形页面,阴影);

        返回true;
    }


}
 
点与圆的位置关系

更新code: -

 专用图形页面图形页面;
私人的ListView ListView的;

@覆盖
公共无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);

    图形页面=(图形页面)findViewById(R.id.mapView);
    ListView的=(的ListView)findViewById(R.id.mylist);

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

    LocationListener的=新GPSLocationListener(图形页面);

    locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            35000,
            0,
            LocationListener的);


    mapView.setStreetView(真正的);
    mapView.setBuiltInZoomControls(真正的);
    mapController = mapView.getController();
    mapController.setZoom(15);
}


    私有类GPSLocationListener实现LocationListener的{

    MapOverlay mapOverlay;

    公共GPSLocationListener(图形页面图形页面){
        mapOverlay =新MapOverlay(这一点,android.R.drawable.star_on);
        名单<覆盖> listOfOverlays =调用MapView.getOverlays();
        listOfOverlays.add(mapOverlay);
    }

    @覆盖
    公共无效onLocationChanged(位置定位){
        如果(位置!= NULL){
            的GeoPoint点=新的GeoPoint(
                    (中间体)(location.getLatitude()* 1E6),
                    (中间体)(location.getLongitude()* 1E6));

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

            // **认为没有必要建立一个新的对象这里**
            mapOverlay.setPointToDraw(点);
            mapView.invalidate();
        }
    }

    @覆盖
    公共无效onProviderDisabled(字符串提供商){
    }

    @覆盖
    公共无效onProviderEnabled(字符串提供商){
    }

    @覆盖
    公共无效onStatusChanged(字符串商,INT地位,捆绑演员){
    }
}


    类MapOverlay扩展覆盖{
    私人的GeoPoint pointToDraw;
    INT [] imageNames =新INT [6];
    私人点mScreenPoints;
    私人位图mBitmap;
    私人油漆mCirclePaint;


    公共MapOverlay(GPSLocationListener gpsLocationListener,诠释的currentUser){
        imageNames [0] =的currentUser;
        mCirclePaint =新的油漆(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setColor(0x30000000);
        mCirclePaint.setStyle(Style.FILL_AND_STROKE);
        mBitmap = BitmapFactory.de codeResource(getResources(),imageNames [0]);
        mScreenPoints =新的点();
    }

    公共无效setPointToDraw(的GeoPoint点){
        pointToDraw =点;
    }

    公众的GeoPoint getPointToDraw(){
        返回pointToDraw;
    }

    公共布尔平局(画布油画,图形页面图形页面,布尔影子,时长){
        super.draw(帆布,图形页面,阴影);
        mScreenPoints = MapView.getProjection()在toPixels(pointToDraw,mScreenPoints)。

        INT totalCircle = 4;
        INT半径= 40;
        INT centerimagesize = 35;

        的for(int i = 1; I< = totalCircle;我++){
            canvas.drawCircle(mScreenPoints.x,mScreenPoints.y,I *半径,mCirclePaint);
        }

        canvas.drawBitmap(mBitmap,(mScreenPoints.x-(centerimagesize / 2)),(mScreenPoints.y-(centerimagesize / 2)),空);
        super.draw(帆布,图形页面,阴影);

        返回true;
    }


}
 

解决方案

下面是几件事情画时要记住:

请不要阻塞主UI线程 记住回收对象。 记住回收对象。 在千万记得要回收的对象。

可能的UI线程阻塞

这code看起来是呼吁回调潜在的昂贵的操作 onLocationChanged()这是非常危险这样做,因为你可能会在ANR。这也许应该在后台的AsyncTask,然后在烤面包上它的结果显示来完成。

 字符串地址= ConvertPointToLocation(点);
Toast.makeText(getBaseContext(),地址,Toast.LENGTH_SHORT).show();
 

资源在地图上更好的管理

相反,每次添加一个新的叠加,确保回收的情况下,只是重新设置它的位置。

 私有类GPSLocationListener实现LocationListener的{
    MapOverlay mOverlay;

    公共GPSLocationListener(){

    }

   @覆盖
   公共无效onLocationChanged(位置定位){
    如果(位置!= NULL){
        的GeoPoint点=新的GeoPoint(
                (中间体)(location.getLatitude()* 1E6),
                (中间体)(location.getLongitude()* 1E6));

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

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

        如果(mOverlay == NULL){
            //此标记添加到叠加总是列表。
            //这东西永远不会改变,所以没有必要做这个逻辑
            //每30秒。加载图像是** **贵
            mOverlay = mMapOverlay =新MapOverlay(这一点,android.R.drawable.star_on);
            名单<覆盖> listOfOverlays =调用MapView.getOverlays();
            listOfOverlays.add(mMapOverlay);
        }
        // **见,没有必要作出一个新的对象这里**
        mOverlay.setPointToDraw(点);

        //这大概可以在其他时间完成。
        //字符串的地址= ConvertPointToLocation(点);
        // Toast.makeText(getBaseContext(),地址,Toast.LENGTH_SHORT).show();

        mapView.invalidate();
    }
 

这code可以重复使用这个标志,只是更新它的位置。你应该只创建一个,如果它不在该列表

更好的图纸

确定下一切记不要在的OnDraw()方法创建对象,如果你没有。 一旦标记知道在哪里画到,你应该拥有一切缓存,以便你可以只专注于绘画。例如:

 公共类MapOverlay {

    私人的GeoPoint pointToDraw;
    INT [] imageNames =新INT [6];
    //这是在屏幕上缓存点,将获得重新灌注在每一个平局
    私人点mScreenPoints;
    //这是缓存德codeD位将每次得出
    私人位图mBitmap;
    //缓存油漆
    私人油漆mCirclePaint;

    公共MapOverlay(GPSLocationListener gpsLocationListener,诠释的currentUser){
      imageNames [0] =的currentUser;
      //这个只需要在这里做一次。它从来没有需要改变。
      mCirclePaint =新的油漆(Paint.ANTI_ALIAS_FLAG);
      mCirclePaint.setColor(0x30000000);
      mCirclePaint.setStyle(Style.FILL_AND_STROKE);
      //我们只需要加载该图像一次,然后自顾自地绘制它dirtyed时。
      mBitmap = BitmapFactory.de codeResource(context.getResources(),imageNames [0]);
      //这点对象将被改变每次调用toPixels(),但该实例可以回收
      mScreenPoints =新的点();
    }

    公共无效setPointToDraw(的GeoPoint点){
      pointToDraw =点;
    }

    公众的GeoPoint getPointToDraw(){
      返回pointToDraw;
    }

    公共布尔平局(画布油画,图形页面图形页面,布尔影子,时长){
      super.draw(帆布,图形页面,阴影);
      //在那里什么也没有设置呢,不做任何图纸的情况下,
      如果(pointToDraw == NULL){
         返回true;
      }
      // --------------平局圈----------------------
      mScreenPoints = MapView.getProjection()在toPixels(pointToDraw,mScreenPoints)。

      INT totalCircle = 4;
      INT半径= 40;
      INT centerimagesize = 35;

      的for(int i = 1; I< = totalCircle;我++){
          canvas.drawCircle(screenPts.x,screenPts.y,I *半径,mCirclePaint);
      }

      canvas.drawBitmap(mBitmap,(screenPts.x-(centerimagesize / 2)),(screenPts.y-(centerimagesize / 2)),空);
      super.draw(帆布,图形页面,阴影);

      返回true;
    }
 

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;
    }


} 

解决方案

Here is a few things to remember when drawing:

Do not block the Main UI Thread Remember Recycle objects. Remember Recycle objects. 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;
    }