<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一直想做一个记录自己运动轨迹的app,只是不知如何绘制轨迹。看了百度地图API中的demo,其实很简单。</span>

核心代码只有两句:

options = new PolylineOptions().color(0xAAFF0000).width(6)
						.points(points);
				mBaiduMap.addOverlay(options);

其中points是坐标的集合,大小size>=2&&size<=1000

完整的测试代码如下:--修改版(解决了中间GPS停止,获取不到数据的情况)


<pre name="code" class="java">package com.kelly.mapdemo;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.DotOptions;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.map.PolylineOptions;
import com.baidu.mapapi.model.LatLng;

public class MyRouteActivity extends Activity {

	// 地图相关
	MapView mMapView;
	BaiduMap mBaiduMap;

	// UI相关
	Button but_start;
	Button but_stop;
	// 定位相关
	private LocationClient mLocationClient;
	BitmapDescriptor mCurrentMarker;
	boolean isFirstLoc = true;// 是否首次定位
	List<LatLng> points = new ArrayList<LatLng>();
	List<LatLng> points_tem = new ArrayList<LatLng>();

	OverlayOptions options;

	// 定时器相关,定时检查GPS是否开启(这里只须检查mLocationClient是否启动)
	Handler handler = new Handler();
	// 是否停止定位服务
	boolean isStopLocClient = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_myroute);
		// 测试点,发布前去掉
		// points.add(new LatLng(34.2376, 108.9923));

		// 启动计时器(每3秒检测一次)
		handler.postDelayed(new MyRunable(), 3000);

		// 初始化地图
		mMapView = (MapView) findViewById(R.id.bmapView);
		mBaiduMap = mMapView.getMap();

		// UI初始化
		but_start = (Button) findViewById(R.id.but_start);
		but_stop = (Button) findViewById(R.id.but_stop);

		// 初始化定位信息
		initLocation();
		// 开始记录并绘制轨迹
		but_start.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				isStopLocClient = false;
				if (!mLocationClient.isStarted()) {
					mLocationClient.start();
				}
			}
		});
		// 结束此次运动,绘制终点
		but_stop.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				isStopLocClient = true;
				if (mLocationClient.isStarted()) {
					// 绘制终点
					drawEnd(points);
					mLocationClient.stop();

				}

			}
		});

	}

	class MyRunable implements Runnable {

		public void run() {
			if (!mLocationClient.isStarted()) {
				mLocationClient.start();
			}
			if (!isStopLocClient) {
				handler.postDelayed(this, 3000);
			}

		}

	}

	/**
	 * 根据数据绘制轨迹
	 * 
	 * @param points2
	 */
	protected void drawMyRoute(List<LatLng> points2) {
		OverlayOptions options = new PolylineOptions().color(0xAAFF0000)
				.width(10).points(points2);
		mBaiduMap.addOverlay(options);
	}

	// 初始化定位
	public void initLocation() {
		// 开启定位图层
		mBaiduMap.setMyLocationEnabled(true);
		// 定位初始化
		mLocationClient = new LocationClient(this);
		mLocationClient.registerLocationListener(new MyLocationListenner());

		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);// 打开gps
		option.setAddrType("all");// 返回的定位结果包含地址信息,(注意如果想获取关于地址的信息,这里必须进行设置)
		option.setCoorType("bd09ll"); // 设置坐标类型
		option.setScanSpan(1000);

		// 设置定位方式的优先级。
		// 当gps可用,而且获取了定位结果时,不再发起网络请求,直接返回给用户坐标。这个选项适合希望得到准确坐标位置的用户。如果gps不可用,再发起网络请求,进行定位。
		option.setPriority(LocationClientOption.GpsFirst);
		// option.setPriority(LocationClientOption.NetWorkFirst);
		mLocationClient.setLocOption(option);

	}

	/**
	 * 定位SDK监听函数
	 */
	class MyLocationListenner implements BDLocationListener {

		@Override
		public void onReceiveLocation(BDLocation location) {
			// map view 销毁后不在处理新接收的位置
			if (location == null || mMapView == null)
				return;
			// 如果不显示定位精度圈,将accuracy赋值为0即可
			MyLocationData locData = new MyLocationData.Builder().accuracy(0)
					.latitude(location.getLatitude())
					.longitude(location.getLongitude()).build();
			mBaiduMap.setMyLocationData(locData);
			LatLng point = new LatLng(location.getLatitude(),
					location.getLongitude());

			points.add(point);
			if (isFirstLoc) {
				points.add(point);
				isFirstLoc = false;
				LatLng ll = new LatLng(location.getLatitude(),
						location.getLongitude());
				MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(ll);
				mBaiduMap.animateMapStatus(u);
			}

			if (points.size() == 5) {

				// 这里绘制起点
				drawStart(points);
			} else if (points.size() > 7) {
				points_tem = points.subList(points.size() - 4, points.size());
				options = new PolylineOptions().color(0xAAFF0000).width(6)
						.points(points_tem);
				mBaiduMap.addOverlay(options);
			}
		}

		public void onReceivePoi(BDLocation poiLocation) {

		}

	}

	@Override
	protected void onStop() {
		isStopLocClient = true;
		mLocationClient.stop();

		super.onStop();
	}

	/**
	 * 绘制起点,取前n个点坐标的平均值绘制起点
	 * 
	 * @param points2
	 */
	public void drawStart(List<LatLng> points2) {
		double myLat = 0.0;
		double myLng = 0.0;

		for (LatLng ll : points2) {
			myLat += ll.latitude;
			myLng += ll.longitude;
		}
		LatLng avePoint = new LatLng(myLat / points2.size(), myLng
				/ points2.size());
		points.add(avePoint);
		options = new DotOptions().center(avePoint).color(0xAA00ff00)
				.radius(15);
		mBaiduMap.addOverlay(options);

	}

	/**
	 * 绘制终点。
	 * 
	 * @param points2
	 */
	protected void drawEnd(List<LatLng> points2) {
		double myLat = 0.0;
		double myLng = 0.0;
		if (points2.size() > 5) {// points肯定大于5,其实不用判断
			for (int i = points2.size() - 5; i < points2.size(); i++) {
				LatLng ll = points2.get(i);
				myLat += ll.latitude;
				myLng += ll.longitude;

			}
			LatLng avePoint = new LatLng(myLat / 5, myLng / 5);
			options = new DotOptions().center(avePoint).color(0xAAff00ff)
					.radius(15);
			mBaiduMap.addOverlay(options);
		}

	}

	@Override
	protected void onPause() {
		mMapView.onPause();
		super.onPause();
	}

	@Override
	protected void onResume() {
		mMapView.onResume();
		super.onResume();
	}

	@Override
	protected void onDestroy() {
		// 退出时销毁定位
		mLocationClient.stop();
		isStopLocClient = true;
		// 关闭定位图层
		mBaiduMap.setMyLocationEnabled(false);
		mMapView.onDestroy();
		mMapView = null;
		super.onDestroy();
	}

}



到最后问题变成了如何利用这些坐标点画出轨迹。

如果每次都将points传入options = new PolylineOptions().color(0xAAFF0000).width(6).points(points);

随着points越来越大,画图也变得越来越慢,优化的地方便是:每次传入option中的点控制为某一常数,如10.这样每次只需绘制10个点便可。最优化可能是每次只画两个点,例如第一次画A1、A2,第二次画A2、A3,但是这样会出现明显的折线。具体如何优化,还请思考,如果你有比较好的想法,麻烦告知一下。注意:千万不可第一次画A1、A2,第二次画A3、A4,因为这样A2、A3会断裂开。

修改一下部分:

1.优化起点与重点的绘制方法。其实就是去几个坐标的平均值。

2.当GPS停止检测时,数据的获取会出现问题,所以需要添加一个定时器,定时检测LocationClient是否启动,若没有启动,则执行启动。

待解决:

1.测试时发现一些噪点,跟轨迹差别很大,需要考虑如何去除这类坐标。

2.绘制的轨迹棱角过于分明,考虑如何使之变得圆滑好看。