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

利用百度地图API实现实时轨迹的显示花了本人不少精力,废话不多说,直接进入主题。

第一步

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

第二步

设置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> 
 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">uses-permission> 

 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE">uses-permission> 
 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">uses-permission> 

 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE">uses-permission>
  
<uses-permission android:name="android.permission.READ_PHONE_STATE">uses-permission> 
 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">uses-permission>
 
 <uses-permission android:name="android.permission.INTERNET" /> 

 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS">uses-permission>

<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS">uses-permission>

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS">uses-permission>

设置AccessKey

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

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

组合后:


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.mybaidumap">

    
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <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.permission.INTERNET" />
    
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
    
    <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:


<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 ListpointList = 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号和大体定位时间到[email protected]," +
                            "会有人追查原因");

                } 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 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 latLngs = new ArrayList();
        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后方可正式使用鹰眼轨迹。

写在后面

本人新手一枚,如有不足望指教。编写这个程序时大量借鉴了这篇博客,表示十分感谢。希望对读者有所帮助。

你可能感兴趣的:(百度地图)