我有一个应用程序,我使用Google播放新的地图服务API,不断跟踪用户的位置.我每隔一秒更新一次位置,我也会检查用户活动,如STILL,TILTING,IN VEHICLE等,以获得更好的位置跟踪.我能够使用我的代码绘制路径,但它不准确,与用户实际驾驶/行走的道路有很大不同.它总是在远离实际用户路径的位置绘制线条.
我的服务: -
public class MyService extends Service implements LocationListener { private final Context mContext; private static MyService mInstance = null; private final static String TAG = "RidingTimerService"; boolean isGPSEnabled = false; private long mStartTime = 0L; private long timeInMilliseconds = 0L; private long timeSwapBuff = 0L; private long updatedTime = 0L; private Handler mHandler = null; private int mHours = 0; // Declaring a Location Manager private LocationManager mLocationManager = null; private Location mCurrentLocation = null; // location private double[][] positions; private long[] times; private final Integer data_points = 2; // how many data points to calculate private double mTravelledDistance = 0.0f; private SharedPreferences mPreferences = null; private ArrayListmDirectionsPoints = new ArrayList (); public boolean mIsPhoneMoving = false; public int mActivityType = -1; int counter = 0; private IntentFilter mBroadcastFilter; private DetectionRequester mDetectionRequester; private DetectionRemover mDetectionRemover; public MyService() { mContext = this; } @Override public void onCreate() { super.onCreate(); mInstance = this; // two arrays for position and time. positions = new double[data_points][2]; times = new long[data_points]; mStartTime = SystemClock.uptimeMillis(); mHandler = new Handler(); mHandler.postDelayed(countDownTimerThread, 0); mPreferences = getSharedPreferences(MyPreferences.PREFERENCES, Context.MODE_PRIVATE); // Create a new Intent filter for the broadcast receiver mBroadcastFilter = new IntentFilter( MyConstants.ACTION_REFRESH_STATUS_LIST); mBroadcastFilter.addCategory(MyConstants.CATEGORY_LOCATION_SERVICES); // Get detection requester and remover objects mDetectionRequester = new DetectionRequester(this); mDetectionRemover = new DetectionRemover(this); mDirectionsPoints.clear(); } /** * Pause the timer */ public void pauseRide() { timeSwapBuff += timeInMilliseconds; mHandler.removeCallbacks(countDownTimerThread); mLocationManager.removeUpdates(this); } /** * Restart the timer */ public void reStartRide() { mStartTime = SystemClock.uptimeMillis(); mHandler.postDelayed(countDownTimerThread, 0); mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); } @Override public void onDestroy() { mHandler.removeCallbacks(countDownTimerThread); mLocationManager.removeUpdates(this); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { getLocation(); return super.onStartCommand(intent, flags, startId); } /** * Timer thread */ private final Runnable countDownTimerThread = new Runnable() { public void run() { mHours = 0; timeInMilliseconds = SystemClock.uptimeMillis() - mStartTime; updatedTime = timeSwapBuff + timeInMilliseconds; int secs = (int) (updatedTime / 1000); final int mins = secs / 60; mHours = mins / 60; secs = secs % 60; final Message msg = new Message(); final Bundle bundle = new Bundle(); bundle.putInt(MyPreferences.BROADCAST_CODES, 300); bundle.putString( "time", String.format("%02d", mHours) + ":" + String.format("%02d", mins) + ":" + String.format("%02d", secs)); msg.setData(bundle); final Intent intent = new Intent(MyConstants.BROADCAST_INTENT); intent.putExtras(bundle); sendBroadcast(intent); mHandler.postDelayed(this, 1000); } }; @Override public IBinder onBind(final Intent intent) { return null; } @Override public void onLocationChanged(final Location location) { if (location != null) { LocationUtils.sLatitude = location.getLatitude(); LocationUtils.sLongitude = location.getLongitude(); mDirectionsPoints.add(new LatLng(LocationUtils.sLatitude, LocationUtils.sLongitude)); riderLocation(location); } else { Log.i(TAG, "Location is not available."); } } /** * Calculate speed, distance and average speed. Send Broadcast which * received by activities * * @param location */ private void riderLocation(final Location location) { DecimalFormat formatter = new DecimalFormat("#0.00"); double distance = 0.0; Double speed = 0.0; long t1 = 0l; final float[] results = new float[3]; positions[counter][0] = location.getLatitude(); positions[counter][1] = location.getLongitude(); times[counter] = location.getTime(); final Bundle bundle = new Bundle(); bundle.putInt(MyPreferences.BROADCAST_CODES, 200); distance = calculateDistance(positions[counter][0], positions[counter][1], positions[(counter + (data_points - 1)) % data_points][0], positions[(counter + (data_points - 1)) % data_points][1]); Location.distanceBetween(positions[counter][0], positions[counter][1], positions[(counter + (data_points - 1)) % data_points][0], positions[(counter + (data_points - 1)) % data_points][1], results); mTravelledDistance += results[0] / 1000; LocationUtils.sDistance = formatter .format((mTravelledDistance * 100.0) / 100.0); final double averageSpeed = mTravelledDistance / mHours; LocationUtils.sAverageSpeed = formatter .format((averageSpeed * 100.0) / 100.0); if (location.hasSpeed()) { speed = location.getSpeed() * 3.6; LocationUtils.sSpeed = speed.intValue(); } else { try { t1 = times[counter] - times[(counter + (data_points - 1)) % data_points]; } catch (final NullPointerException e) { // all good, just not enough data yet. } speed = (distance / t1) * 3.6; LocationUtils.sSpeed = speed.intValue(); counter = (counter + 1) % data_points; } LocationUtils.sLatitude = location.getLatitude(); LocationUtils.sLongitude = location.getLongitude(); final Intent intent = new Intent(MyConstants.BROADCAST_INTENT); intent.putExtras(bundle); sendBroadcast(intent); } public void onProviderDisabled(final String arg0) { Toast.makeText(getApplicationContext(), "Gps Disabled", Toast.LENGTH_LONG).show(); } public void onProviderEnabled(final String arg0) { Toast.makeText(getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show(); } /** * @return location */ public Location getLocation() { try { mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); // getting GPS status isGPSEnabled = mLocationManager .isProviderEnabled(LocationManager.GPS_PROVIDER); if (!isGPSEnabled) { // no network provider is enabled showSettingsAlert(); } else { // if GPS Enabled get lat/long using GPS Services if (isGPSEnabled) { mLocationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, this); Log.d(TAG, "GPS Enabled"); if (mCurrentLocation == null) { if (mLocationManager != null) { mCurrentLocation = mLocationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (mCurrentLocation != null) { LocationUtils.sLatitude = mCurrentLocation .getLatitude(); LocationUtils.sLongitude = mCurrentLocation .getLongitude(); } } } else { LocationUtils.sLatitude = mCurrentLocation .getLatitude(); LocationUtils.sLongitude = mCurrentLocation .getLongitude(); } } } } catch (Exception e) { e.printStackTrace(); } return mCurrentLocation; } /** * @fn public static RidingTimerService getInstance() * @brief returns instance of the service. * @return RidingTimerService instance */ public static MyService getInstance() { return mInstance; } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } /** * Reset all the values stored in Preferences */ public void resetAllText() { mPreferences.edit().putString(MyPreferences.LATITUDE, "0.0").commit(); mPreferences.edit().putString(MyPreferences.LONGITUDE, "0.0") .commit(); mPreferences.edit().putString(MyPreferences.SPEED, "0.0").commit(); mPreferences.edit().putString(MyPreferences.AVERAGE_SPEED, "0.0") .commit(); mPreferences.edit().putString(MyPreferences.DISTANCE, "0.0").commit(); } /** * Respond to "Start" button by requesting activity recognition updates. * * @param view * The view that triggered this method. */ public void onStartUpdates() { // Pass the update request to the requester object mDetectionRequester.requestUpdates(); } /** * Respond to "Stop" button by canceling updates. * * @param view * The view that triggered this method. */ public void onStopUpdates() { // Pass the remove request to the remover object mDetectionRemover.removeUpdates(mDetectionRequester .getRequestPendingIntent()); /* * Cancel the PendingIntent. Even if the removal request fails, * canceling the PendingIntent will stop the updates. */ mDetectionRequester.getRequestPendingIntent().cancel(); } /** * Function to show settings alert dialog On pressing Settings button will * lauch Settings Options * */ public void showSettingsAlert() { AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext); alertDialog.setTitle("GPS"); alertDialog.setMessage("GPS is not enabled. Do you want to enable it?"); // On pressing Settings button alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS); mContext.startActivity(intent); } }); // on pressing cancel button alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); // Showing Alert Message alertDialog.show(); } /** * @return List of Direction points */ public ArrayList getDirectionsPoints() { if (mDirectionsPoints != null) { return mDirectionsPoints; } else { mDirectionsPoints = new ArrayList (); return mDirectionsPoints; } } /** * Calculate distance * * @param lat1 * @param lon1 * @param lat2 * @param lon2 * @return */ private double calculateDistance(final double lat1, final double lon1, final double lat2, final double lon2) { // haversine great circle distance approximation, returns meters final double theta = lon1 - lon2; double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta)); dist = Math.acos(dist); dist = rad2deg(dist); dist = dist * 60; // 60 nautical miles per degree of seperation dist = dist * 1852; // 1852 meters per nautical mile return dist; } private double deg2rad(final double deg) { return (deg * Math.PI / 180.0); } private double rad2deg(final double rad) { return (rad * 180.0 / Math.PI); } }
我每1秒保持一次位置更新,活动识别每3秒更新一次.我能够获取位置,但在Google地图中未正确绘制路径.
绘制路径的代码: -
public class MapsActivity extends FragmentActivity { private static GoogleMap mGoogleMap = null; private static final String TAG = "MapsActivity"; private Button mBtnStartRide, mBtnPauseRide, mBtnStopRide = null; private static TextView mTxtLatLong, mTxtTimer, mTxtTotalSize, mTxtSpeed = null; private static PolylineOptions mPolyLineOptions = null; // Storing the directions returned by the direcction api private SharedPreferences mPreferences = null; private MapsBroadcastReceiver receiver = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); receiver = new MapsBroadcastReceiver(); mPreferences = getSharedPreferences(TestPreferences.PREFERENCES, Context.MODE_PRIVATE); mTxtLatLong = (TextView) findViewById(R.id.txtLatLong); mTxtTimer = (TextView) findViewById(R.id.txtTimer); mTxtTotalSize = (TextView) findViewById(R.id.txtDirectionsSize); mTxtSpeed = (TextView) findViewById(R.id.txtSpeed); mBtnStartRide = (Button) findViewById(R.id.btn_start_ride); mBtnPauseRide = (Button) findViewById(R.id.btn_pause_ride); mBtnStopRide = (Button) findViewById(R.id.btn_stop_ride); final Button mBtnCenter = (Button) findViewById(R.id.btn_center); mBtnCenter.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { animateCameraTo(); } }); mBtnStartRide.setOnClickListener(btnStartRideClickListener); mBtnPauseRide.setOnClickListener(btnPauseRideClickListener); mBtnStopRide.setOnClickListener(btnStopRideClickListener); initilizeMap(); } /** * Start Ride Button Click Listener */ private OnClickListener btnStartRideClickListener = new OnClickListener() { @Override public void onClick(View v) { if (mPreferences.getBoolean(TestPreferences.IS_RIDE_PAUSE, false)) { if (MyService.getInstance() != null) { MyService.getInstance().reStartRide(); } } else { startService(new Intent(MapsActivity.this, MyService.class)); } mPreferences.edit().putBoolean(TestPreferences.IS_RIDE_START, true) .commit(); mPreferences.edit().remove(TestPreferences.IS_RIDE_PAUSE).commit(); mPreferences.edit().remove(TestPreferences.IS_RIDE_STOPPED) .commit(); mBtnStartRide.setVisibility(View.GONE); mBtnPauseRide.setVisibility(View.VISIBLE); mBtnStopRide.setVisibility(View.VISIBLE); } }; /** * Start Ride Button Click Listener */ private OnClickListener btnPauseRideClickListener = new OnClickListener() { @Override public void onClick(View v) { MyService.getInstance().pauseRide(); mPreferences.edit().putBoolean(TestPreferences.IS_RIDE_PAUSE, true) .commit(); mPreferences.edit() .putBoolean(TestPreferences.IS_RIDE_START, false).commit(); mBtnStartRide.setVisibility(View.VISIBLE); mBtnPauseRide.setVisibility(View.GONE); mBtnStopRide.setVisibility(View.VISIBLE); } }; /** * Stop Ride Button Click Listener */ private OnClickListener btnStopRideClickListener = new OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(MapsActivity.this, MyService.class)); mPreferences.edit().remove(TestPreferences.IS_RIDE_PAUSE).commit(); mPreferences.edit() .putBoolean(TestPreferences.IS_RIDE_START, false).commit(); mPreferences.edit() .putBoolean(TestPreferences.IS_RIDE_STOPPED, true).commit(); mBtnStartRide.setVisibility(View.VISIBLE); mBtnPauseRide.setVisibility(View.GONE); mBtnStopRide.setVisibility(View.GONE); } }; @Override protected void onResume() { super.onResume(); registerReceiver(receiver, new IntentFilter( MyConstants.BROADCAST_INTENT)); initilizeMap(); if (mPreferences.getBoolean(TestPreferences.IS_RIDE_START, false)) { mBtnStartRide.setVisibility(View.GONE); mBtnPauseRide.setVisibility(View.VISIBLE); mBtnStopRide.setVisibility(View.VISIBLE); } else if (mPreferences .getBoolean(TestPreferences.IS_RIDE_PAUSE, false)) { mBtnStartRide.setVisibility(View.VISIBLE); mBtnPauseRide.setVisibility(View.GONE); mBtnStopRide.setVisibility(View.VISIBLE); } else if (mPreferences.getBoolean(TestPreferences.IS_RIDE_STOPPED, false)) { // Show start button and gone Pause & Stop both mBtnStartRide.setVisibility(View.VISIBLE); mBtnPauseRide.setVisibility(View.GONE); mBtnStopRide.setVisibility(View.GONE); } else { // Show start button and gone Pause & Stop both mBtnStartRide.setVisibility(View.VISIBLE); mBtnPauseRide.setVisibility(View.GONE); mBtnStopRide.setVisibility(View.GONE); } setAllText(); } @Override protected void onPause() { super.onPause(); unregisterReceiver(receiver); } @Override protected void onDestroy() { super.onDestroy(); mGoogleMap = null; } /** * Function to load map. If map is not created it will create it for you * */ private void initilizeMap() { if (mGoogleMap == null) { mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById( R.id.map)).getMap(); // check if map is created successfully or not if (mGoogleMap == null) { Toast.makeText(getApplicationContext(), "Sorry! unable to create maps", Toast.LENGTH_SHORT) .show(); } else { mPolyLineOptions = new PolylineOptions().width(6).color( Color.BLUE); mGoogleMap.setTrafficEnabled(true); mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true); mGoogleMap.getUiSettings().setRotateGesturesEnabled(true); mGoogleMap.getUiSettings().setCompassEnabled(true); mGoogleMap.getUiSettings().setZoomGesturesEnabled(true); mGoogleMap.getUiSettings().setZoomControlsEnabled(true); if (MyService.getInstance() != null && MyService.getInstance().getDirectionsPoints() != null && !MyService.getInstance().getDirectionsPoints() .isEmpty() && MyService.getInstance().getDirectionsPoints() .size() >= 1) { mGoogleMap.addMarker(new MarkerOptions() .position( MyService.getInstance() .getDirectionsPoints().get(0)) .anchor(0.8f, 1.0f).title("Your Location")); animateCameraTo(MyService.getInstance() .getDirectionsPoints().get(0).latitude, MyService.getInstance().getDirectionsPoints() .get(0).longitude); } } } else { mPolyLineOptions = new PolylineOptions().width(6).color(Color.BLUE); mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true); mGoogleMap.getUiSettings().setRotateGesturesEnabled(true); mGoogleMap.getUiSettings().setCompassEnabled(true); mGoogleMap.getUiSettings().setZoomGesturesEnabled(true); mGoogleMap.getUiSettings().setZoomControlsEnabled(true); if (MyService.getInstance() != null && MyService.getInstance().getDirectionsPoints() != null && !MyService.getInstance().getDirectionsPoints() .isEmpty() && MyService.getInstance().getDirectionsPoints().size() >= 1) { Log.i(TAG, "Lat long in resume2222222222 = " + MyService.getInstance().getDirectionsPoints() .get(0).latitude + ", " + MyService.getInstance().getDirectionsPoints() .get(0).longitude); mGoogleMap.addMarker(new MarkerOptions() .position( MyService.getInstance().getDirectionsPoints() .get(0)).anchor(0.8f, 1.0f) .title("Your Location")); animateCameraTo(MyService.getInstance().getDirectionsPoints() .get(0).latitude, MyService.getInstance() .getDirectionsPoints().get(0).longitude); } } } /** * @author Scorpion * */ private class MapsBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getExtras().getInt(TestPreferences.BROADCAST_CODES)) { case 100: showErrorDialog(intent.getExtras().getInt( TestPreferences.BROADCAST_CODES)); break; case 200: setAllText(); break; case 300: if (intent.getExtras().getString("time") != null) { mTxtTimer.setText("Timer - " + intent.getExtras().getString("time")); } else { mTxtTimer.setText("Timer - 00:00:00"); } break; default: break; } if (MyService.getInstance() != null && !MyService.getInstance().getDirectionsPoints() .isEmpty() && MyService.getInstance().getDirectionsPoints().size() == 1) { mGoogleMap.addMarker(new MarkerOptions() .position( MyService.getInstance().getDirectionsPoints() .get(0)).anchor(0.8f, 1.0f) .title("Your Location")); } } } /** * */ public void setAllText() { mTxtLatLong.setText("Lat - " + LocationUtils.sLatitude + ", Lng - " + LocationUtils.sLongitude); mTxtSpeed.setText("Speed - " + LocationUtils.sSpeed); mTxtTotalSize.setText("Distance - " + LocationUtils.sDistance); } /** * Animate to position on Google Maps * * @param lat * @param lng */ private void animateCameraTo() { // Saving the points in a polyline if (MyService.getInstance() != null && MyService.getInstance().getDirectionsPoints() != null && !MyService.getInstance().getDirectionsPoints().isEmpty()) { mPolyLineOptions.geodesic(true); mPolyLineOptions.addAll(MyService.getInstance() .getDirectionsPoints()); // Drawing the path on the map Polyline route = mGoogleMap.addPolyline(mPolyLineOptions); int index = MyService.getInstance().getDirectionsPoints().size() - 1; CameraPosition cameraPosition = new CameraPosition.Builder() .target(MyService.getInstance().getDirectionsPoints() .get(index)).zoom(20).build(); mGoogleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); } } /** * Animate to position on Google Maps * * @param lat * @param lng */ private void animateCameraTo(final double lat, final double lng) { // Saving the points in a polyline if (MyService.getInstance() != null && MyService.getInstance().getDirectionsPoints() != null && !MyService.getInstance().getDirectionsPoints().isEmpty()) { mPolyLineOptions.geodesic(true); mPolyLineOptions.addAll(MyService.getInstance() .getDirectionsPoints()); // Drawing the path on the map mGoogleMap.addPolyline(mPolyLineOptions); CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(lat, lng)).zoom(20).build(); mGoogleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); } } /** * Show a dialog returned by Google Play services for the connection error * code * * @param errorCode * An error code returned from onConnectionFailed */ private void showErrorDialog(int errorCode) { // Get the error dialog from Google Play services Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, MapsActivity.this, LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST); // If Google Play services can provide an error dialog if (errorDialog != null) { // Create a new DialogFragment in which to show the error dialog ErrorDialogFragment errorFragment = new ErrorDialogFragment(); // Set the dialog in the DialogFragment errorFragment.setDialog(errorDialog); // Show the error dialog in the DialogFragment errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG); } } }
协调结果从位置提供了: - 23.030392522689674,72.5570888165469,23.030408166940184,72.55708600340783,23.030451207802273,72.55708215400317,23.030448342522195,72.5570607428365,23.03045605637773,72.55702903413072,23.03046687434995,72.55702007867455,23.030481227996425,72.55702017125606,23.03049188235562,72.55701618151457,23.030501580461667,72.55701051075931,23.030506644074638,72.55700568837983,23.030510243171772, 72.55699463185964,23.03051656621021,72.55698811382064,23.030523584332027,72.55698589863236,23.030527893257556,72.5569835596,23.03052731568596,72.55698681171178,23.030533706759005,72.55699683791043,23.03053795413862,72.5570022232021,23.03054422659466,72.55700788646914,23.030550353227323,72.5570133047868,23.03056167617575,72.5570171806126,23.030572274532982,72.55702744953462,23.03057623596164,72.55703687229187,23.03058756510295,72.55703589208271,23.030591797598742,72.5570396833694,23.030597556470788,72.55703954449652,23.030602030769657,72.55704359454182,23.030606735158617,72.55704993131606,23.030611670633565,72.55705060538087,23.030618875802222,72.55705181604097,23.030629137631596,72.55705043471286,23.030651405170016,72.55705440295588,23.03066642161307,72.55705285209174,23.030690454277963,72.55703884780276,23.030708214416187, 72.55703489882957,23.03072341369183,72.5570340196122,23.030737371000015,72.55703289416898,23.03075088423441,72.55703750535102,23.030767572625837,72.55704489874579,23.030794398930176,72.55703870239826,23.03081655932613,72.55702474270966,23.030827505666753,72.5570121351611,23.03083720431765,72.55700390084714,23.03084624667527,72.55700122660554,23.030859495795887,72.55699948514881,23.030870357210333,72.55699625144317,23.030881843633054
这段代码可行
GoogleMap map; // ... get a map. // Add a thin red line from London to New York. Polyline line = map.addPolyline(new PolylineOptions() .add(new LatLng(51.5, -0.1), new LatLng(40.7, -74.0)) .width(5) .color(Color.RED));