<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.绘制的轨迹棱角过于分明,考虑如何使之变得圆滑好看。