欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-03 18:11:51
...

利用百度地图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.permission.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号和大体定位时间到aaa@qq.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后方可正式使用鹰眼轨迹。

写在后面

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