2

現在、場所が変更され、10メートルの距離が移動した後、35秒ごとに描画しCircleています。Current Location

LocationChangedそのため、場所が変更されるとすぐに(35秒と10メートル移動)、この機能を実装しましたCircle on the Google Maps on the Current Location

問題文:-

My App is running very slow。時々私のアプリはハングしますか?私のコードが以下に書いた方法ではそれほど効率的ではないためかもしれませんか?

基本的には、35秒ごとに10メートルの距離を移動した後、現在の場所に円を描く必要があります。

コードに問題はありますか?スムーズに実行するには、これをさらに改善する方法などの考えがあります。

@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) {
    }
}

これは、円を描いているMapOverlayクラスです。

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


}

更新されたコード:-

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


} 
4

1 に答える 1

1

描画するときに覚えておくべきことがいくつかあります。

  1. メイン UI スレッドをブロックしない
  2. オブジェクトのリサイクルを思い出してください。
  3. オブジェクトのリサイクルを思い出してください。
  4. そして常にオブジェクトをリサイクルすることを忘れないでください。

UI スレッドのブロックの可能性

このコードは、コールバックでコストがかかる可能性のあるアクションを呼び出しているように見えonLocationChanged()ますが、ANR になる可能性があるため、これを実行するのは非常に危険です。これはおそらくバックグラウンドの AsyncTask で実行し、その結果にトーストを表示する必要があります。

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

マップ上のリソースの管理の改善

毎回新しいオーバーレイを追加する代わりに、必ずインスタンスをリサイクルして、その位置をリセットしてください。

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

このコードは、このマーカーを再利用して、その位置を更新するだけです。リストにない場合は、1 つだけ作成してください。

より良い描画

次に、必要がない場合は onDraw() メソッドでオブジェクトを作成しないことを覚えておいてください。マーカーがどこに描画するかを認識したら、描画に集中できるようにすべてをキャッシュする必要があります。例えば:

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;
    }
于 2012-09-17T00:41:43.133 に答える