騰訊地圖GPS軌跡回放-安卓篇

前言

當(dāng)我們使用地圖進(jìn)行開(kāi)發(fā)時(shí)杈湾,利用已經(jīng)錄制好的軌跡進(jìn)行軌跡回放來(lái)檢查導(dǎo)航的準(zhǔn)確性是十分常用的手段,并且上一篇已經(jīng)講完了關(guān)于地圖使用時(shí)GPS軌跡文件的錄制紊遵,現(xiàn)在對(duì)于安卓系統(tǒng)下使用騰訊導(dǎo)航SDK進(jìn)行軌跡回放做一個(gè)分享

前期準(zhǔn)備

騰訊導(dǎo)航SDK依賴于騰訊地圖SDK蝠检、騰訊定位SDK,具體權(quán)限的開(kāi)通需要去lbs.qq.com 的官網(wǎng)控制臺(tái)去操作,另外導(dǎo)航SDK的權(quán)限可以聯(lián)系小助手咨詢(如下圖所示)肝箱,這里就不多做探討

16222560693250.jpg

軌跡回放正片

系統(tǒng)架構(gòu)

16224265311888.jpg

GPS回放系統(tǒng)分成兩部分:GPSPlaybackActivity 和 GPSPlaybackEngine。
GPSPlayback負(fù)責(zé)和外界的交互稀蟋,主要是信息的傳遞和導(dǎo)航SDK的交互煌张,而GPSPlaybackEngine負(fù)責(zé)具體的讀取文件和將定位點(diǎn)通過(guò)多線程runnable機(jī)制灌入listener。

開(kāi)始軌跡回放

BaseNaviActivity.java

baseNaviActivity 主要是對(duì)于導(dǎo)航SDK naviView部分的生命周期的管理退客,必須實(shí)現(xiàn)骏融,否則不能進(jìn)行導(dǎo)航!


/**
 * 導(dǎo)航 SDK {@link CarNaviView} 初始化與周期管理類萌狂。
 */
public abstract class BaseNaviActivity {

    private static Context mApplicationContext;

    protected CarNaviView mCarNaviView;

    // 建立了TencentCarNaviManager 單例模式档玻,也可以直接調(diào)用TencentCarNaviManager來(lái)建立自己的carNaviManager
    public static final Singleton<TencentCarNaviManager> mCarManagerSingleton =
            new Singleton<TencentCarNaviManager>() {
                @Override
                protected TencentCarNaviManager create() {
                    return new TencentCarNaviManager(mApplicationContext);
                }
            };

    public static TencentCarNaviManager getCarNaviManager(Context appContext) {
        mApplicationContext = appContext;
        return mCarManagerSingleton.get();
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutID());
        super.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mApplicationContext = getApplicationContext();
        mCarNaviView = findViewById(R.id.tnk_car_navi_view);
        mCarManagerSingleton.get().addNaviView(mCarNaviView);
    }

    public int getLayoutID() {
        return R.layout.tnk_activity_navi_base;
    }

    protected View getCarNaviViewChaild() {
        final int count = mCarNaviView.getChildCount();
        if (0 >= count) {
            return mCarNaviView;
        }
        return mCarNaviView.getChildAt(count - 1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (!isDestoryMap()) {
            return;
        }
        mCarManagerSingleton.get().removeAllNaviViews();
        if (mCarNaviView != null) {
            mCarNaviView.onDestroy();
        }
//        mCarManagerSingleton.destory();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mCarNaviView != null) {
            mCarNaviView.onStart();
        }
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        if (mCarNaviView != null) {
            mCarNaviView.onRestart();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mCarNaviView != null) {
            mCarNaviView.onResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mCarNaviView != null) {
            mCarNaviView.onPause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mCarNaviView != null) {
            mCarNaviView.onStop();
        }
    }

    protected boolean isDestoryMap() {
        return true;
    }
}

GPSPlaybackActivity.java

這一部分主要是對(duì)于導(dǎo)航 SDK的交互和添加導(dǎo)航UI部分初始化工作。注意導(dǎo)航sdk一定要先算路茫藏,再開(kāi)始導(dǎo)航误趴。算路可以取得GPS文件的首行為起點(diǎn),末行為終點(diǎn)务傲。

用到的fields

    private static final String LOG_TAG = "[GpsPlayback]";

    // gps 文件路徑
    private String mGpsTrackPath;
    // gps 軌跡的起終點(diǎn)
    private NaviPoi mFrom, mTo;

    // 是否是84坐標(biāo)系
    private boolean isLocation84 = true;

因?yàn)樵贕PSPlaybackEngine已經(jīng)進(jìn)行了listener監(jiān)聽(tīng)凉当,所以需要對(duì)于導(dǎo)航SDK進(jìn)行灌點(diǎn)

// 騰訊定位sdk的listener
    private TencentLocationListener listener = new TencentLocationListener() {
        @Override
        public void onLocationChanged(TencentLocation tencentLocation, int error, String reason) {
            if (error != TencentLocation.ERROR_OK || tencentLocation == null) {
                return;
            }
            Log.d(LOG_TAG, "onLocationChanged : "
                    + ", latitude" + tencentLocation.getLatitude()
                    + ", longitude: " + tencentLocation.getLongitude()
                    + ", provider: " + tencentLocation.getProvider()
                    + ", accuracy: " + tencentLocation.getAccuracy());

            // 將定位點(diǎn)灌入導(dǎo)航SDK
            // mCarManagerSingleton是使用導(dǎo)航SDK的carNaviManager創(chuàng)建的單例枣申,開(kāi)發(fā)者可以自己實(shí)現(xiàn)
            mCarManagerSingleton.get().updateLocation(ConvertHelper
                    .convertToGpsLocation(tencentLocation), error, reason);
        }

        @Override
        public void onStatusUpdate(String provider, int status, String description) {
            Log.d(LOG_TAG, "onStatusUpdate provider: " + provider
                    + ", status: " + status
                    + ", desc: " + description);

            // 更新GPS狀態(tài).
            mCarManagerSingleton.get().updateGpsStatus(provider, status, description);
        }
    };

onCreate方法初始化UI和添加callback

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

        // 獲取GPS文件軌跡路徑,這里可以由開(kāi)發(fā)者自己獲取
        mGpsTrackPath = getIntent().getStringExtra("gpsTrackPath");
        if (mGpsTrackPath == null || mGpsTrackPath.isEmpty()) {
            return;
        }

        initUi();
        addTencentCallback();

        new Handler().post(() -> {
        
            // 目的獲取每條軌跡的arraylist
            ArrayList<String> gpsLineStrs = readGpsFile(mGpsTrackPath);
            if (gpsLineStrs == null || gpsLineStrs.isEmpty()) {
                return;
            }
            // 獲取起終點(diǎn)
            getFromAndTo(gpsLineStrs);
            if (mFrom == null || mTo == null) {
                return;
            }
            final Handler handlerUi = new Handler(Looper.getMainLooper());
            handlerUi.post(() -> searchAndStartNavigation());
        });

    }
    

private void initUi() {
        mCarManagerSingleton.get().setInternalTtsEnabled(true);

        final int margin = CommonUtils.dip2px(this, 36);
        // 全覽模式的路線邊距
        mCarNaviView.setVisibleRegionMargin(margin, margin, margin, margin);
        mCarNaviView.setAutoScaleEnabled(true);
        mCarManagerSingleton.get().setMulteRoutes(true);
        mCarNaviView.setNaviMapActionCallback(mCarManagerSingleton.get());

        // 使用默認(rèn)UI
        CarNaviInfoPanel carNaviInfoPanel = mCarNaviView.showNaviInfoPanel();
        carNaviInfoPanel.setOnNaviInfoListener(() -> {
            mCarManagerSingleton.get().stopNavi();
            finish();
        });
        CarNaviInfoPanel.NaviInfoPanelConfig config = new CarNaviInfoPanel.NaviInfoPanelConfig();
        config.setRerouteViewEnable(true);             // 重算按鈕
        carNaviInfoPanel.setNaviInfoPanelConfig(config);
    }

    private void addTencentCallback() {
        mCarManagerSingleton.get().addTencentNaviCallback(mTencentCallback);
    }
    
    private TencentNaviCallback mTencentCallback = new TencentNaviCallback() {
        @Override
        public void onStartNavi() { }

        @Override
        public void onStopNavi() { }

        @Override
        public void onOffRoute() { }

        @Override
        public void onRecalculateRouteSuccess(int recalculateType,
                                              ArrayList<RouteData> routeDataList) { }
        @Override
        public void onRecalculateRouteSuccessInFence(int recalculateType) { }

        @Override
        public void onRecalculateRouteFailure(int recalculateType,
                                              int errorCode, String errorMessage) { }

        @Override
        public void onRecalculateRouteStarted(int recalculateType) { }

        @Override
        public void onRecalculateRouteCanceled() { }

        @Override
        public int onVoiceBroadcast(NaviTts tts) {
            return 0;
        }

        @Override
        public void onArrivedDestination() { }

        @Override
        public void onPassedWayPoint(int passPointIndex) { }

        @Override
        public void onUpdateRoadType(int roadType) { }

        @Override
        public void onUpdateParallelRoadStatus(ParallelRoadStatus parallelRoadStatus) {

        }

        @Override
        public void onUpdateAttachedLocation(AttachedLocation location) { }

        @Override
        public void onFollowRouteClick(String routeId, ArrayList<LatLng> latLngArrayList) { }
    };

readGpsFile方法

private ArrayList<String> readGpsFile(String fileName) {
        ArrayList<String> gpsLineStrs = new ArrayList<>();
        BufferedReader reader = null;
        try {
            File file = new File(fileName);
            InputStream is = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(is));

            String line;
            while ((line = reader.readLine()) != null) {
                gpsLineStrs.add(line);
            }
            return gpsLineStrs;
        } catch (Exception e) {
            Log.e(LOG_TAG, "startMockTencentLocation Exception", e);
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                Log.e(LOG_TAG, "startMockTencentLocation Exception", e);
                e.printStackTrace();
            }
        }
        return null;
    }

getFromAndTo方法看杭,獲取起終點(diǎn)為進(jìn)行算路

    private void getFromAndTo(ArrayList<String> gpsLineStrs) {
        final int size;
        if ((size = gpsLineStrs.size()) < 2) {
            return;
        }
        final String firstLine = gpsLineStrs.get(0);
        final String endLine = gpsLineStrs.get(size - 1);
        try {
            final String[] fromParts = firstLine.split(",");
            mFrom = new NaviPoi(Double.valueOf(fromParts[1]), Double.valueOf(fromParts[0]));
            final String[] endParts = endLine.split(",");
            mTo = new NaviPoi(Double.valueOf(endParts[1]), Double.valueOf(endParts[0]));
        } catch (Exception e) {
            mFrom = null;
            mTo = null;
        }
    }

算路searchAndStartNavigation()

可以使用導(dǎo)航SDK的算路方法并且獲取算路成功和失敗的回調(diào)


    private void searchAndStartNavigation() {
        mCarManagerSingleton.get()
                .searchRoute(new TencentRouteSearchCallback() {
                    @Override
                    public void onRouteSearchFailure(int i, String s) {
                        toast("路線規(guī)劃失敗");
                    }

                    @Override
                    public void onRouteSearchSuccess(ArrayList<RouteData> arrayList) {
                        if (arrayList == null || arrayList.isEmpty()) {
                            toast("未能召回路線");
                            return;
                        }
                        handleGpsPlayback();
                    }
                });
    }
    

調(diào)用GpsPlaybackEngine方法忠藤,進(jìn)行l(wèi)isten定位,然后開(kāi)始導(dǎo)航

    private void handleGpsPlayback() {

// 與GpsPlaybackEngine 進(jìn)行交互, 添加locationListener
GpsPlaybackEngine.getInstance().addTencentLocationListener(listener);

//與GpsPlaybackEngine 進(jìn)行交互泊窘,開(kāi)始定位
        GpsPlaybackEngine.getInstance().startMockTencentLocation(mGpsTrackPath, isLocation84);
        try {
            mCarManagerSingleton.get().startNavi(0);
        } catch (Exception e) {
            toast(e.getMessage());
        }
    }

結(jié)束導(dǎo)航

    @Override
    protected void onDestroy() {
// 與GpsPlaybackEngine 進(jìn)行交互, removelocationListener
mCarManagerSingleton.get().removeTencentNaviCallback(mTencentCallback);
//與GpsPlaybackEngine 進(jìn)行交互熄驼,結(jié)束定位GpsPlaybackEngine.getInstance().removeTencentLocationListener(listener);
        GpsPlaybackEngine.getInstance().stopMockLocation();
        if (mCarManagerSingleton.get().isNavigating()) {
        // 結(jié)束導(dǎo)航
            mCarManagerSingleton.get().stopNavi();
        }
        super.onDestroy();
    }

GPSPlaybackEngine.java

這一部分主要是對(duì)于GPS文件進(jìn)行讀取并且提供外界可用的add/removelistener方法像寒,start/stopMockLocation方法
因?yàn)橐宔ngine運(yùn)行在自己的線程烘豹,所以使用runnable機(jī)制

public class GpsPlaybackEngine implements Runnable{

            // 代碼在下方
}

而使用到的fields

// Tencent軌跡Mock, TencentLocationListener需要利用騰訊定位SDK獲取
private ArrayList<TencentLocationListener> mTencentLocationListeners = new ArrayList<>();
    
// 獲取的location數(shù)據(jù)
private List<String> mDatas = new ArrayList<String>();
     
private boolean mIsReplaying = false;

private boolean mIsMockTencentLocation = true;

private Thread mMockGpsProviderTask = null;

// 是否已經(jīng)暫停
private boolean mPause = false;

private double lastPointTime = 0;
private double sleepTime = 0;

關(guān)鍵方法

  • listener相關(guān)
    // 添加listener
    public void addTencentLocationListener(TencentLocationListener listener) {
        if (listener != null) {
            mTencentLocationListeners.add(listener);
        }
    }

    // 移除listener 
    public void removeTencentLocationListener(TencentLocationListener listener) {
        if (listener != null) {
            mTencentLocationListeners.remove(listener);
        }
    }
  • 開(kāi)始/關(guān)閉模擬軌跡
    /*
     * 模擬軌跡
     * @param context
     * @param fileName 軌跡文件絕對(duì)路徑
     */
    public void startMockTencentLocation(String fileName, boolean is84) {

       // 首先清除以前的data
        mDatas.clear();
        // 判斷是否是84坐標(biāo)系
        mIsMockTencentLocation = !is84;
        BufferedReader reader = null;
        try {
            File file = new File(fileName);
            InputStream is = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(is));

            String line;
            while ((line = reader.readLine()) != null) {
                mDatas.add(line);
            }
            if (mDatas.size() > 0) {
                mIsReplaying = true;
                synchronized (this) {
                    mPause = false;
                }
                // 開(kāi)啟異步線程
                mMockGpsProviderTask = new Thread(this);
                mMockGpsProviderTask.start();
            }
        } catch (Exception e) {
            Log.e(TAG, "startMockTencentLocation Exception", e);
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                Log.e(TAG, "startMockTencentLocation Exception", e);
                e.printStackTrace();
            }
        }
    }
    /**
     * 退出應(yīng)用前也需要調(diào)用停止模擬位置,否則手機(jī)的正常GPS定位不會(huì)恢復(fù)
     */
    public void stopMockTencentLocation() {
        try {
            mIsReplaying = false;
            mMockGpsProviderTask.join();
            mMockGpsProviderTask = null;
            lastPointTime = 0;
        } catch (Exception e) {
            Log.e(TAG, "stopMockTencentLocation Exception", e);
            e.printStackTrace();
        }
    }
  • runnable相關(guān)
 @Override
    public void run() {
        for (String line : mDatas) {
            if (!mIsReplaying) {
                Log.e(TAG, "stop gps replay");
                break;
            }
            if (TextUtils.isEmpty(line)) {
                continue;
            }

            try {
                Thread.sleep(getSleepTime(line) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean mockResult;
            mockResult = mockTencentLocation(line);
            if (!mockResult) {
                break;
            }

            try {
                checkToPauseThread();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

使用到的private方法

private void checkToPauseThread() throws InterruptedException {
        synchronized (this) {
            while (mPause) {
                wait();
            }
        }
}

private int getSleepTime(String line) {
    try {
        String[] parts = line.split(",");
        double time = Double.valueOf(parts[6]);
        time = (int) Math.floor(time);
        if(lastPointTime != 0) {
            sleepTime = time  - lastPointTime; // 單位s诺祸,取整數(shù)
        }
        lastPointTime = time;
    }catch (Exception e) {
    
    }
    return (int)sleepTime;
}

private boolean mockTencentLocation(String line) {
    try {
        String[] parts = line.split(",");

        double latitude = Double.valueOf(parts[1]);
        double longitude = Double.valueOf(parts[0]);
        float accuracy = Float.valueOf(parts[2]);
        float bearing = Float.valueOf(parts[3]);
        float speed = Float.valueOf(parts[4]);
        double altitude = Double.valueOf(parts[7]);
        double time = Double.valueOf(parts[6]);

        String buildingId;
        String floorName;
        if (parts.length >= 10) {
            buildingId = parts[8];
            floorName = parts[9];
        } else {
            buildingId = "";
            floorName = "";
        }

        if (!mIsMockTencentLocation) {
            double[] result = CoordinateConverter.wgs84togcj02(longitude, latitude);
            longitude = result[0];
            latitude = result[1];
        }

        GpsPlaybackEngine.MyTencentLocation location = new GpsPlaybackEngine.MyTencentLocation();
        location.setProvider("gps");
        location.setLongitude(longitude);
        location.setLatitude(latitude);
        location.setAccuracy(accuracy);
        location.setDirection(bearing);
        location.setVelocity(speed);
        location.setAltitude(altitude);
        location.setBuildingId(buildingId);
        location.setFloorName(floorName);
        location.setRssi(4);
        location.setTime(System.currentTimeMillis());
//          location.setTime((long) time * 1000);

        for (TencentLocationListener listener : mTencentLocationListeners) {
            if (listener != null) {
                String curTime;
                if (location != null && location.getTime() != 0) {
                    long millisecond = location.getTime();
                    Date date = new Date(millisecond);
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss");
                    curTime = format.format(date);
                } else {
                    curTime = "null";
                }
                Log.e(TAG, "time : " + curTime
                        + ", longitude : " + longitude
                        + " , latitude : " + latitude);

                listener.onLocationChanged(location, 0, "");
                listener.onStatusUpdate(LocationManager.GPS_PROVIDER, mMockGpsStatus, "");
            }
        }
    } catch(Exception e) {
        Log.e(TAG, "Mock Location Exception", e);
        // 如果未開(kāi)位置模擬携悯,這里可能出異常
        e.printStackTrace();
        return false;
    }
    return true;
}

CoordinateConverter.wg84togcj02

    /**
     * WGS84轉(zhuǎn)GCJ02(火星坐標(biāo)系)
     * 
     * @param lng WGS84坐標(biāo)系的經(jīng)度
     * @param lat WGS84坐標(biāo)系的緯度
     * @return 火星坐標(biāo)數(shù)組
     */
    public static double[] wgs84togcj02(double lng, double lat) {
        if (out_of_china(lng, lat)) {
            return new double[] { lng, lat };
        }
        double dlat = transformlat(lng - 105.0, lat - 35.0);
        double dlng = transformlng(lng - 105.0, lat - 35.0);
        double radlat = lat / 180.0 * pi;
        double magic = Math.sin(radlat);
        magic = 1 - ee * magic * magic;
        double sqrtmagic = Math.sqrt(magic);
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
        double mglat = lat + dlat;
        double mglng = lng + dlng;
        return new double[] { mglng, mglat };
    }

內(nèi)部類MyTencentLocation implements 定位sdk的接口

class MyTencentLocation implements TencentLocation {
        /**
         * 緯度
         */
        private double latitude = 0;
        /**
         * 經(jīng)度
         */
        private double longitude = 0;
        /**
         * 精度
         */
        private float accuracy = 0;
        /**
         * gps方向
         */
        private float direction = -1;
        /**
         * 速度
         */
        private float velocity = 0;
        /**
         * 時(shí)間
         */
        private long time = 0;
        /**
         * 海拔高度
         */
        private double altitude = 0;
        /**
         * 定位來(lái)源
         */
        private String provider = "";
        /**
         * GPS信號(hào)等級(jí)
         */
        private int rssi = 0;

        /**
         * 手機(jī)的機(jī)頭方向
         */
        private float phoneDirection = -1;

        private String buildingId = "";

        private String floorName = "";

        private  String fusionProvider = "";

        @Override
        public String getProvider() {
            return provider;
        }

        @Override
        public String getSourceProvider() {
            return null;
        }

        @Override
        public String getFusionProvider() {
            return fusionProvider;
        }

        @Override
        public String getCityPhoneCode() {
            return null;
        }

        @Override
        public double getLatitude() {
            return latitude;
        }

        @Override
        public double getLongitude() {
            return longitude;
        }

        @Override
        public double getAltitude() {
            return latitude;
        }

        @Override
        public float getAccuracy() {
            return accuracy;
        }

        @Override
        public String getName() {
            return null;
        }

        @Override
        public String getAddress() {
            return null;
        }

        @Override
        public String getNation() {
            return null;
        }

        @Override
        public String getProvince() {
            return null;
        }

        @Override
        public String getCity() {
            return null;
        }

        @Override
        public String getDistrict() {
            return null;
        }

        @Override
        public String getTown() {
            return null;
        }

        @Override
        public String getVillage() {
            return null;
        }

        @Override
        public String getStreet() {
            return null;
        }

        @Override
        public String getStreetNo() {
            return null;
        }

        @Override
        public Integer getAreaStat() {
            return null;
        }

        @Override
        public List<TencentPoi> getPoiList() {
            return null;
        }

        @Override
        public float getBearing() {
            return direction;
        }

        @Override
        public float getSpeed() {
            return velocity;
        }

        @Override
        public long getTime() {
            return time;
        }

        @Override
        public long getElapsedRealtime() {
            return time;
        }

        @Override
        public int getGPSRssi() {
            return rssi;
        }

        @Override
        public String getIndoorBuildingId() {
            return buildingId;
        }

        @Override
        public String getIndoorBuildingFloor() {
            return floorName;
        }

        @Override
        public int getIndoorLocationType() {
            return 0;
        }

        @Override
        public double getDirection() {
            return phoneDirection;
        }

        @Override
        public String getCityCode() {
            return null;
        }

        @Override
        public TencentMotion getMotion() {
            return null;
        }

        @Override
        public int getGpsQuality() {
            return 0;
        }

        @Override
        public float getDeltaAngle() {
            return 0;
        }

        @Override
        public float getDeltaSpeed() {
            return 0;
        }

        @Override
        public int getCoordinateType() {
            return 0;
        }

        @Override
        public int getFakeReason() {
            return 0;
        }

        @Override
        public int isMockGps() {
            return 0;
        }

        @Override
        public Bundle getExtra() {
            return null;
        }

        @Override
        public int getInOutStatus() {
            return 0;
        }

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public void setAccuracy(float accuracy) {
            this.accuracy = accuracy;
        }

        public void setDirection(float direction) {
            this.direction = direction;
        }

        public void setVelocity(float velocity) {
            this.velocity = velocity;
        }

        public void setTime(long time) {
            this.time = time;
        }

        public void setAltitude(double altitude) {
            this.altitude = altitude;
        }

        public void setProvider(String provider) {
            this.provider = provider;
        }

        public void setFusionProvider(String fusionProvider) { this.fusionProvider = fusionProvider; }

        public void setRssi(int rssi) {
            this.rssi = rssi;
        }

        public void setPhoneDirection(float phoneDirection) {
            this.phoneDirection = phoneDirection;
        }

        public void setBuildingId(String buildingId) {
            this.buildingId = buildingId;
        }

        public void setFloorName(String floorName) {
            this.floorName = floorName;
        }
    }

效果展示

最終根據(jù)已經(jīng)錄制好的軌跡(具體錄制方法可以參見(jiàn)上期騰訊位置服務(wù)軌跡錄制-安卓篇),從中國(guó)技術(shù)交易大廈到北京西站的gps軌跡進(jìn)行回放筷笨,并通過(guò)導(dǎo)航sdk進(jìn)行展示如下

image.png

作者:騰訊位置服務(wù)

鏈接:https://my.oschina.net/u/4209404/blog/5048899

來(lái)源:開(kāi)源中國(guó)

著作權(quán)歸作者所有憔鬼。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處胃夏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末轴或,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子仰禀,更是在濱河造成了極大的恐慌照雁,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件答恶,死亡現(xiàn)場(chǎng)離奇詭異饺蚊,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)悬嗓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門污呼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人包竹,你說(shuō)我怎么就攤上這事燕酷。” “怎么了周瞎?”我有些...
    開(kāi)封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵苗缩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我堰氓,道長(zhǎng)挤渐,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任双絮,我火速辦了婚禮浴麻,結(jié)果婚禮上得问,老公的妹妹穿的比我還像新娘。我一直安慰自己软免,他們只是感情好宫纬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著膏萧,像睡著了一般漓骚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榛泛,一...
    開(kāi)封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天蝌蹂,我揣著相機(jī)與錄音,去河邊找鬼曹锨。 笑死孤个,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沛简。 我是一名探鬼主播齐鲤,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼椒楣!你這毒婦竟也來(lái)了给郊?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捧灰,失蹤者是張志新(化名)和其女友劉穎淆九,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體凤壁,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吩屹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拧抖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煤搜。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖唧席,靈堂內(nèi)的尸體忽然破棺而出擦盾,到底是詐尸還是另有隱情,我是刑警寧澤淌哟,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布迹卢,位于F島的核電站,受9級(jí)特大地震影響徒仓,放射性物質(zhì)發(fā)生泄漏腐碱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望症见。 院中可真熱鬧喂走,春花似錦、人聲如沸谋作。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遵蚜。三九已至帖池,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吭净,已是汗流浹背睡汹。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留攒钳,地道東北人帮孔。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓雷滋,卻偏偏與公主長(zhǎng)得像不撑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子晤斩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言 在地圖的使用中焕檬,尤其在導(dǎo)航場(chǎng)景下,進(jìn)行GPS軌跡錄制是十分必要并且有用的澳泵,本文會(huì)對(duì)于安卓系統(tǒng)下的軌跡錄制部分...
    _bugMaker閱讀 1,149評(píng)論 0 1
  • 前言 在地圖的使用中实愚,尤其在導(dǎo)航場(chǎng)景下,進(jìn)行GPS軌跡錄制是十分必要并且有用的兔辅,本文會(huì)對(duì)于安卓系統(tǒng)下的軌跡錄制部分...
    Mr船長(zhǎng)大人閱讀 356評(píng)論 0 2
  • 前言 在地圖接入使用中腊敲,很多開(kāi)發(fā)者咨詢我們騰訊位置服務(wù)是否支持軌跡回放功能,所以今天特意將我們JavaScript...
    Mr船長(zhǎng)大人閱讀 2,444評(píng)論 0 6
  • 前言 在地圖的使用中维苔,尤其在導(dǎo)航場(chǎng)景下碰辅,進(jìn)行GPS軌跡錄制是十分必要并且有用的,本文會(huì)對(duì)于安卓系統(tǒng)下的軌跡錄制部分...
    _草木一秋閱讀 508評(píng)論 0 4
  • 引入騰訊地圖定位SDK文檔 官方API接口地址 官方首頁(yè)[https://lbs.qq.com/geo/index...
    盛夏吃西瓜閱讀 4,352評(píng)論 0 1