您的位置:首页 > 其它

百度地图--实时显示轨迹

2017-05-27 23:00 706 查看
利用百度地图API实现实时轨迹的显示花了本人不少精力,废话不多说,直接进入主题。

第一步

因为要实现轨迹的显示,配置环境是必不可少的。我同时用到了鹰眼轨迹Android SDKAndroid定位SDK,配置过程那两个链接有详细的说明,这里也不多说了。我配置后的图片:



第二步

设置AndroidManifest.xml,前提是你已经申请了密钥

1、在Application标签中声明SERVICE组件,每个APP拥有自己独立的鹰眼追踪service和定位service

<service
android:name="com.baidu.trace.LBSTraceService"
android:enabled="true"
android:process=":remote">
</service>
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" />


2、声明使用权限:

<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入对象存储BOS数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用于写入对象存储BOS数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
<!-- 用于加快GPS首次定位-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission>
<!-- 用于Android M及以上系统,申请加入忽略电池优化白名单-->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>


设置AccessKey

在Mainfest.xml正确设置AccessKey(ak),如果设置错误将会导致鹰眼服务无法正常使用。需在Application标签中加入以下代码,并填入开发者自己的 Android 类型 ak。ak 申请方法参见申请密钥

<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="AK" />       //key:开发者申请的Key


组合后:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.mybaidumap">

<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 用于读取手机当前的状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permis
1411d
sion.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- SD卡读取权限,用于写入对象存储BOS数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 用于加快GPS首次定位-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<!-- 用于Android M及以上系统,申请加入忽略电池优化白名单-->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" />
<service
android:name="com.baidu.trace.LBSTraceService"
android:enabled="true"
android:process=":remote">
</service>

<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="FmGWStTyEpEj5WtfHfzCoNVkGvzB02ki" />

<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userPortrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>

</manifest>


为了防止屏幕旋转后程序被杀死才会加入(当然你也可以编写屏幕旋转后的指令):

android:screenOrientation="userPortrait"


第三步

编辑布局文件,一个Button,一个MapView:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.mybaidumap.MainActivity">
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
/>
<Button
android:id="@+id/start_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="轨迹"
android:textSize="20sp"
android:layout_alignRight="@+id/bmapView" />
</RelativeLayout>


第四步

接下来是java代码:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.Poi;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.map.PolylineOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.trace.LBSTraceClient;
import com.baidu.trace.Trace;
import com.baidu.trace.api.entity.LocRequest;
import com.baidu.trace.api.entity.OnEntityListener;
import com.baidu.trace.api.track.HistoryTrackRequest;
import com.baidu.trace.api.track.HistoryTrackResponse;
import com.baidu.trace.api.track.OnTrackListener;
import com.baidu.trace.api.track.SortType;
import com.baidu.trace.api.track.SupplementMode;
import com.baidu.trace.api.track.TrackPoint;
import com.baidu.trace.model.CoordType;
import com.baidu.trace.model.LocationMode;
import com.baidu.trace.model.OnTraceListener;
import com.baidu.trace.model.ProcessOption;
import com.baidu.trace.model.PushMessage;
import com.baidu.trace.model.TraceLocation;
import com.baidu.trace.model.TransportMode;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static java.lang.Math.sqrt;

public class MainActivity extends Activity {
MapView mMapView = null;
BaiduMap mBaiduMap = null;
Button staButton;   //开始记录轨迹按钮
boolean flag = true;
boolean isFirstTrace = true;

public LocationClient mLocClient = null;

private static OnTraceListener startTraceListener = null;
private static OnEntityListener entityListener = null;
private RefreshThread refreshThread = null;
private static BitmapDescriptor realtimeBitmap = null;
private static OverlayOptions overlay; //起始点图标overlay
private static PolylineOptions polyline;
private List<LatLng>pointList = new ArrayList<>();

private Trace trace;
private LBSTraceClient client;
private LocRequest locRequest = null;

boolean isFirstLoc = true;  //是否首次定位
//   查询历史轨迹request选项定义
boolean isNeedObjectStorage = false;
long serviceId = ******;    //轨迹服务id
int gatherInterval = 3; //定位周期,秒
int packInterval = 10;  //打包回传周期,秒
int tag = 1;    //请求标识
String entityName = "";

public BDLocationListener myListener = new BDLocationListener() {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
//mMapView 销毁后不再处理新接收的位置信息
if(bdLocation == null || mBaiduMap == null) return;
MyLocationData locData = new MyLocationData.Builder()
.accuracy(bdLocation.getRadius())
.direction(100).latitude(bdLocation.getLatitude())
.longitude(bdLocation.getLongitude()).build();

mBaiduMap.setMyLocationData(locData);
if(isFirstLoc){
isFirstLoc = false;
//设置地图中心点以及缩放级别
LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
MapStatusUpdate u = MapStatusUpdateFactory.newLatLngZoom(ll,18);
mBaiduMap.animateMapStatus(u);
/* BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory.fromResource(R.drawable.icon_marka4);
OverlayOptions option = new MarkerOptions()
.position(ll)
.icon(mCurrentMarker);
mBaiduMap.addOverlay(option); */
//获取定位结果
StringBuffer sb = new StringBuffer(256);

sb.append("time : ");
sb.append(bdLocation.getTime());    //获取定位时间

sb.append("\nerror code : ");
sb.append(bdLocation.getLocType());    //获取类型类型

sb.append("\nlatitude : ");
sb.append(bdLocation.getLatitude());    //获取纬度信息

sb.append("\nlontitude : ");
sb.append(bdLocation.getLongitude());    //获取经度信息

sb.append("\nradius : ");
sb.append(bdLocation.getRadius());    //获取定位精准度

if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){

// GPS定位结果
sb.append("\nspeed : ");
sb.append(bdLocation.getSpeed());    // 单位:公里每小时

sb.append("\nsatellite : ");
sb.append(bdLocation.getSatelliteNumber());    //获取卫星数

sb.append("\nheight : ");
sb.append(bdLocation.getAltitude());    //获取海拔高度信息,单位米

sb.append("\ndirection : ");
sb.append(bdLocation.getDirection());    //获取方向信息,单位度

sb.append("\naddr : ");
sb.append(bdLocation.getAddrStr());    //获取地址信息

sb.append("\ndescribe : ");
sb.append("gps定位成功");

} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){

// 网络定位结果
sb.append("\naddr : ");
sb.append(bdLocation.getAddrStr());    //获取地址信息

sb.append("\noperationers : ");
sb.append(bdLocation.getOperators());    //获取运营商信息

sb.append("\ndescribe : ");
sb.append("网络定位成功");

} else if (bdLocation.getLocType() == BDLocation.TypeOffLineLocation) {

// 离线定位结果
sb.append("\ndescribe : ");
sb.append("离线定位成功,离线定位结果也是有效的");

} else if (bdLocation.getLocType() == BDLocation.TypeServerError) {

sb.append("\ndescribe : ");
sb.append("服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com," +
"会有人追查原因");

} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkException) {

sb.append("\ndescribe : ");
sb.append("网络不同导致定位失败,请检查网络是否通畅");

} else if (bdLocation.getLocType() == BDLocation.TypeCriteriaException) {

sb.append("\ndescribe : ");
sb.append("无法获取有效定位依据导致定位失败,一般是由于手机的原因," +
"处于飞行模式下一般会造成这种结果,可以试着重启手机");

}

sb.append("\nlocationdescribe : ");
sb.append(bdLocation.getLocationDescribe());    //位置语义化信息

List<Poi> list = bdLocation.getPoiList();    // POI数据
if (list != null) {
sb.append("\npoilist size = : ");
sb.append(list.size());
for (Poi p : list) {
sb.append("\npoi= : ");
sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
}
}

Log.i("BaiduLocationApiDem", sb.toString());
Toast.makeText(getApplicationContext(),bdLocation.getAddrStr(),
Toast.LENGTH_SHORT).show();
}

}

@Override
public void onConnectHotSpotMessage(String s, int i) {
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//在使用SDK各组件之前初始化context信息,传入ApplicationContext
//注意该方法要再setContentView方法之前实现
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
init(); //相关变量初始化
initOnEntityListener(); //初始化实体监听器
initOnStartTraceListener(); //轨迹监听器

}

private void init(){

mMapView = (MapView) findViewById(R.id.bmapView);
staButton = (Button) findViewById(R.id.start_btn);    //记录轨迹按钮

mBaiduMap = mMapView.getMap();
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
mBaiduMap.setMyLocationEnabled(true);
mLocClient = new LocationClient(getApplicationContext()); //实例化LocationClient类
mLocClient.registerLocationListener(myListener);  //注册监听函数
this.setLocationOption();
mLocClient.start();

entityName = getImei(getApplicationContext());
client = new LBSTraceClient(getApplicationContext());
//设置定位模式,这里我选择的是只用GPS定位,这样精度高些        client.setLocationMode(LocationMode.Device_Sensors);
trace = new Trace(serviceId, entityName,isNeedObjectStorage);  //实例化轨迹服务
//设置位置采集和打包周期
client.setInterval(gatherInterval, packInterval);
//开启轨迹服务
client.startTrace(trace, startTraceListener);
realtimeBitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_start);

}

private void initOnEntityListener(){

/**
* 地图点击,标注显示
*/
mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
public void onMapClick(LatLng point) {
//在此处理点击事件
}

public boolean onMapPoiClick(MapPoi poi) {
//在此处理底图标注点击事件

}
});

/**
* 实时显示轨迹按钮监听
*/
staButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (isFirstTrace) {
//开始实时显示轨迹
startRefreshThread(true);
mBaiduMap.clear();
isFirstTrace = false;
//开始定位采集
client.startGather(startTraceListener);
} else {
//结束显示实时轨迹
isFirstTrace = true;
pointList.clear();//清空点集
mBaiduMap.clear();
//停止收集轨迹点
client.stopGather(startTraceListener);
//停止刷新进程
startRefreshThread(false);

}
}
});

/**
*  实体状态监听器
*/
entityListener = new OnEntityListener(){

@Override
//            接收最新的轨迹点
public void onReceiveLocation(TraceLocation traceLocation) {
super.onReceiveLocation(traceLocation);
LatLng point = new LatLng(traceLocation.getLatitude(),traceLocation.getLongitude());
if(pointList.size()==0){
overlay = new MarkerOptions().position(point)
.icon(realtimeBitmap).zIndex(9).draggable(true);
mBaiduMap.addOverlay(overlay);
pointList.add(point);
}else {
LatLng last = pointList.get(pointList.size() - 1);
double distance = getDistance(point,last);
if (distance < 80 && distance>0) {

pointList.add(point);
drawRealtimePoint(point,last);

}
}

}
};
}
/**
* 计算两点之间的距离
*/
public static double getDistance(LatLng point1,LatLng point2)
{
double lat1 = point1.latitude*100000;
double lng1 = point1.longitude*100000;
double lat2 = point2.latitude*100000;
double lng2 = point2.longitude*100000;
return sqrt((lat1-lat2)*(lat1-lat2)+(lng1-lng2)*(lng1-lng2));
}

/**
*  追踪开始
*/
private void initOnStartTraceListener() {

// 实例化开启轨迹服务回调接口
startTraceListener = new OnTraceListener() {
@Override
public void onStartTraceCallback(int i, String s) {
Log.i("TAG", "onTraceCallback=" + s);
if(i == 0 || i == 10006){
}
}

@Override
public void onStopTraceCallback(int i, String s) {

}

@Override
public void onStartGatherCallback(int i, String s) {

}

@Override
public void onStopGatherCallback(int i, String s) {

}

@Override
public void onPushCallback(byte b, PushMessage pushMessage) {
Log.i("TAG", "onTracePushCallback=" + pushMessage);

}

};

}
private class RefreshThread extends Thread{

protected boolean refresh = true;

public void run(){

while(refresh){
queryRealtimeTrack();
System.out.println("线程更新"+pointList.size());
try{
Thread.sleep(packInterval * 1000);
}catch(InterruptedException e){
System.out.println("线程休眠失败");
}
}

}
}

/**
* 查询实时线路
*/
private void queryRealtimeTrack(){

locRequest = new LocRequest(tag,serviceId);
client.queryRealTimeLoc(locRequest,entityListener);

}

/**
* 启动刷新线程
* @param isStart
*/
private void startRefreshThread(boolean isStart){

if(refreshThread == null){
refreshThread = new RefreshThread();
}

refreshThread.refresh = isStart;

if(isStart){
if(!refreshThread.isAlive()){
refreshThread.start();
}
}
else{
refreshThread = null;
}

}

/**
* 画出实时线路点
* @param point
*/
private void drawRealtimePoint(LatLng point,LatLng last){

//           每次画两个点
List<LatLng> latLngs = new ArrayList<LatLng>();
latLngs.add(last);
latLngs.add(point);
polyline = new PolylineOptions().width(10).color(Color.BLUE).points(latLngs);
mBaiduMap.addOverlay(polyline);

}

/**
*  获取手机识别码
*/
private String getImei(Context context){
String mImei = "NULL";
try {
mImei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
} catch (Exception e) {
mImei = "NULL";
}
return mImei;
}

/**
* 设置定位选项
*/
private void setLocationOption() {
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);  //打开GPS
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); //设置定位模式
option.setCoorType("bd09ll"); //返回的定位结果是百度经纬度默认值gcj02
//option.setScanSpan(2000);  //设置发起定位请求的间隔时间为2000ms
option.setOpenAutoNotifyMode(); //设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化
// 就会主动回调给开发者,该模式下开发者无需再关心定位间隔是多少,定位SDK本身发现位置变化就会及时回调给开发者
option.setIsNeedAddress(true);  //返回的定位结果包含地址信息
option.setNeedDeviceDirect(true);  //返回的定位结果包含手机机头的方向
mLocClient.setLocOption(option);

}

@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
mMapView = null;
mLocClient.stop();
client.stopTrace(trace,startTraceListener);

}

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

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

@Override
public void onStart() {
super.onStart();

}

@Override
public void onStop() {
super.onStop();

}

}


提示:使用任何鹰眼轨迹接口前,必须先在轨迹管理台中创建鹰眼工程,获得servie_id后方可正式使用鹰眼轨迹。

写在后面

本人新手一枚,如有不足望指教。编写这个程序时大量借鉴了这篇博客,表示十分感谢。希望对读者有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: