1. 程式人生 > >百度地圖的基本應用和遇到的坑

百度地圖的基本應用和遇到的坑

百度地圖的整合和使用

1. 第一步

既然是整合,自然需要先去看一下百度地圖的相關網站,下面會陸續使用到這個網站。http://lbsyun.baidu.com/index.php?title=%E9%A6%96%E9%A1%B5

2. 申請sdk

註冊完賬號,之後就可以建立自己的應用啦,這個過程很簡單,不需要人工通過。相關操作具體參考http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key

3. 下載

首先要清楚自己需要的百度地圖含有什麼內容啦,在這裡,我主要使用了基礎地圖,離線定位和計算工具的功能,下載開發包就行了,如果想要自行了解百度地圖的,建議可以具體看看示例程式碼。相關地址http://lbsyun.baidu.com/sdk/download?selected=mapsdk_basicmap,mapsdk_searchfunction,mapsdk_lbscloudsearch,mapsdk_calculationtool,mapsdk_radar

4. 整合

使用很簡單,主要是新增依賴和複製我們下載的包中的檔案,詳情見http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject

5. 使用

前五點內容在百度相關的網站說明中還是很詳細的,具體的使用其實在demo中也是有的。

6. 許可權

<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"
/>
<uses-permission android:name="android.permission.GET_TASKS"/> <uses-permission android:name="android.permission.WRITE_SETTINGS"/> <!-- 這個許可權用於進行網路定位 --> <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"/>

7. application新增

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

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

8. 基礎地圖

以下的內容都是我集成了官方的百度地圖Demo,寫的內容,主要的區別就是官方是分開的,我是都整合在一起了,不過不影響使用,建議看官方Demo,後續我會接著說明一些Api的使用。
//1.基礎地圖,建議可修改預設城市
mMapView = (MapView) findViewById(R.id.bmapView);
mBaiduMap = mMapView.getMap();
//設定地圖狀態
LatLng center = new LatLng(39.915071, 116.403907); // 預設 天安門
MapStatus build = new MapStatus.Builder().target(center).zoom(18.0f).build();
MapStatusUpdate mapstatus = MapStatusUpdateFactory.newMapStatus(build);
mBaiduMap.animateMapStatus(mapstatus);

所需的座標,可通過百度提供的百度地圖座標拾取系統獲取。點選前往獲取座標
當然最後寫上生命週期是必要的。這個後面會有一起提到

9.基礎定位

//獲取感測器管理服務 用於箭頭指示方向
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

//2.定位
mBaiduMap.setMyLocationEnabled(true);
mBaiduMap.setOnMapLongClickListener(this);

mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null));
mLocationClient = new LocationClient(this);// 宣告LocationClient類
mLocationClient.registerLocationListener(myListener); // 註冊監聽函式

//開啟定位
option = new LocationClientOption();
option.setOpenGps(true);
option.setCoorType("bd09ll");
option.setProdName("shouxiu");
option.setScanSpan(1000);// 設定發起定位請求的間隔時間為10000ms
mLocationClient.setLocOption(option);
mLocationClient.start();

/**
 * 定位開啟後位置監聽
 */
@SuppressLint("ShowToast")
public class MyLocationListener implements BDLocationListener {

    @Override
    public void onReceiveLocation(BDLocation location) {
        if (location == null || mMapView == null) {
            return;
        }

        // 當位置改變時,獲取當前經緯度
        mCurrentLat = location.getLatitude();
        mCurrentLon = location.getLongitude();
        mCurrentAccracy = location.getRadius();
        locData = new MyLocationData.Builder()
                .accuracy(location.getRadius())
                // 此處設定開發者獲取到的方向資訊,順時針0-360
                .direction(mCurrentDirection).latitude(location.getLatitude())
                .longitude(location.getLongitude()).build();
        mBaiduMap.setMyLocationData(locData);

        //為了有效顯示預設地址12,定位地址18
        if (isFirstLoc) {
            isFirstLoc = false;
            LatLng ll = new LatLng(location.getLatitude(),
                    location.getLongitude());
            MapStatus.Builder builder = new MapStatus.Builder();
            builder.target(ll).zoom(18.0f);
            mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));

        }
    }

}

/**
 * 手機自帶的方向感應
 * @param sensorEvent
 */
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    double x = sensorEvent.values[SensorManager.DATA_X];
    if (Math.abs(x - lastX) > 1.0) {
        mCurrentDirection = (int) x;
        locData = new MyLocationData.Builder()
                .accuracy(mCurrentAccracy)
                // 此處設定開發者獲取到的方向資訊,順時針0-360
                .direction(mCurrentDirection).latitude(mCurrentLat)
                .longitude(mCurrentLon).build();
        mBaiduMap.setMyLocationData(locData);
    }
    lastX = x;

}

生命週期

@Override
protected void onDestroy() {
    // 退出時銷燬定位
    mLocationClient.stop();
    //銷燬POI搜尋
    mPoiSearch.destroy();
    mSuggestionSearch.destroy();
    // 關閉定點陣圖層
    mBaiduMap.setMyLocationEnabled(false);
    mMapView.onDestroy();
    mMapView = null;
    //線路規劃
    if (mRoutePlanSearch!= null) {
        mRoutePlanSearch.destroy();
    }
    super.onDestroy();
}

@Override
protected void onResume() {
    mMapView.onResume();
    super.onResume();
    //為系統的方向感測器註冊監聽器
    mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
            SensorManager.SENSOR_DELAY_UI);
}

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

@Override
protected void onStop() {
    mSensorManager.unregisterListener(this);
    super.onStop();
}

10.POI搜尋

// 初始化搜尋模組,註冊搜尋事件監聽
mPoiSearch = PoiSearch.newInstance();   mPoiSearch.setOnGetPoiSearchResultListener(poiListener);

// 初始化建議搜尋模組,註冊建議搜尋事件監聽
mSuggestionSearch = SuggestionSearch.newInstance();
mSuggestionSearch.setOnGetSuggestionResultListener(mSuggestionResultListener);

//填入搜尋城市
editCity = (EditText) findViewById(R.id.city);
//填入搜尋關鍵字
keyWorldsView = (AutoCompleteTextView) findViewById(R.id.searchkey);
//關鍵字輸入後,提示下拉框顯示介面卡
sugAdapter = new ArrayAdapter<>(this,
        android.R.layout.simple_dropdown_item_1line);
keyWorldsView.setAdapter(sugAdapter);
keyWorldsView.setThreshold(1);

//當輸入關鍵字變化時,動態更新建議列表
keyWorldsView.addTextChangedListener(new TextWatcher() {

    //省略程式碼

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        if (cs.length() <= 0) {
            return;
        }

   //使用建議搜尋服務獲取建議列表,結果在onSuggestionResult()中更新
    mSuggestionSearch
            .requestSuggestion((new SuggestionSearchOption())
                    .keyword(cs.toString()).city(editCity.getText().toString()));
}
});


//響應城市內搜尋按鈕點選事件
public void searchButtonProcess(View v) {
    searchType = 1;
    String citystr = editCity.getText().toString();
    String keystr = keyWorldsView.getText().toString();

    // 設定檢索引數
    PoiCitySearchOption citySearchOption = new PoiCitySearchOption();
    citySearchOption.city(citystr);// 城市
    citySearchOption.keyword(keystr);// 關鍵字
    citySearchOption.pageCapacity(15);// 預設每頁10條
    citySearchOption.pageNum(loadIndex);// 分頁編號
    // 發起檢索請求
    mPoiSearch.searchInCity(citySearchOption);
}

//響應周邊搜尋按鈕點選事件
public void searchNearbyProcess(View v) {
    searchType = 2;
    mCenter = new LatLng(mCurrentLat, mCurrentLon);
    System.out.println(mCurrentLat);
    System.out.println(mCurrentLon);

    PoiNearbySearchOption nearbySearchOption = new PoiNearbySearchOption();
    nearbySearchOption.location(mCenter);
    nearbySearchOption.keyword(keyWorldsView.getText().toString());
    nearbySearchOption.radius(1000);// 檢索半徑,單位是米
    nearbySearchOption.pageNum(loadIndex);
    mPoiSearch.searchNearby(nearbySearchOption);// 發起附近檢索請求
}

//檢索結果標記類
private class MyPoiOverlay extends PoiOverlay {

    public MyPoiOverlay(BaiduMap baiduMap) {
        super(baiduMap);
    }

    @Override
    public boolean onPoiClick(int index) {
        super.onPoiClick(index);
        PoiInfo poi = getPoiResult().getAllPoi().get(index);
        // if (poi.hasCaterDetails) {
        mPoiSearch.searchPoiDetail((new PoiDetailSearchOption())
                .poiUid(poi.uid));
        // }
        return true;
    }
}

//POI檢索監聽
OnGetPoiSearchResultListener poiListener = new OnGetPoiSearchResultListener() {

    public void onGetPoiResult(PoiResult result) {
        //獲取POI檢索結果
        if (result == null || result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
            Toast.makeText(MainActivity.this, "未找到結果", Toast.LENGTH_LONG)
                    .show();
            return;
        }
        if (result.error == SearchResult.ERRORNO.NO_ERROR) {
            mBaiduMap.clear();
            PoiOverlay overlay = new MyPoiOverlay(mBaiduMap);
            mBaiduMap.setOnMarkerClickListener(overlay);
            overlay.setData(result);
            overlay.addToMap();
            overlay.zoomToSpan();
            if (searchType == 2) {
                showNearbyArea(mCenter, radius);
            }

            return;
        }
        if (result.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD) {

            // 當輸入關鍵字在本市沒有找到,但在其他城市找到時,返回包含該關鍵字資訊的城市列表
            String strInfo = "在";
            for (CityInfo cityInfo : result.getSuggestCityList()) {
                strInfo += cityInfo.city;
                strInfo += ",";
            }
            strInfo += "找到結果";
            Toast.makeText(MainActivity.this, strInfo, Toast.LENGTH_LONG)
                    .show();
        }
    }

    public void onGetPoiDetailResult(PoiDetailResult result) {
        //獲取Place詳情頁檢索結果
        if (result.error != SearchResult.ERRORNO.NO_ERROR) {
            Toast.makeText(MainActivity.this, "抱歉,未找到結果", Toast.LENGTH_SHORT)
                    .show();
        } else {
            mEndLocation = result.getLocation();
            Toast.makeText(MainActivity.this, result.getName() + ": " + result.getAddress(), Toast.LENGTH_SHORT)
                    .show();
        }
    }

    @Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {

    }
};

//輸入關鍵字推薦結果
private ArrayList<String> suggest;
OnGetSuggestionResultListener mSuggestionResultListener = new OnGetSuggestionResultListener() {
    @Override
    public void onGetSuggestionResult(SuggestionResult res) {
        if (res == null || res.getAllSuggestions() == null) {
            return;
        }
        suggest = new ArrayList<>();
        for (SuggestionResult.SuggestionInfo info : res.getAllSuggestions()) {
            if (info.key != null) {
                suggest.add(info.key);
            }
        }
        sugAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_dropdown_item_1line, suggest);
        keyWorldsView.setAdapter(sugAdapter);
        sugAdapter.notifyDataSetChanged();
    }
};

11.路徑規劃

這一塊的程式碼有點長,所以這裡也就不做複述了,建議檢視官方Demo,在這裡提一些小的需求,長按標記前往地點,然後路徑規劃

//長按標記前往地址
@Override
public void onMapLongClick(LatLng latLng) {
    //全域性終點座標
    mEndLocation = latLng;
    MarkerOptions ooA = new MarkerOptions().position(latLng).icon(bdA);
    mBaiduMap.clear();
    mBaiduMap.addOverlay(ooA);
}
然後在定位監聽中獲取當前座標,有了兩個座標,就可以做路徑規劃了

12.遇到的坑

自定義地圖的設定,官方必須要將mapview新增到FrameLayout,當時不清楚,就不斷地試,走了不少彎路。其次就是關於公司的一個需求,去除地鐵線路,這個我就笑了,線是去了,但是留下了文字框(地鐵線上關於線路介紹的),這個框不管做什麼設定,都存在。

13.綜述

差不多了,這篇部落格篇幅有些長了。關於Api的使用就放到下一篇中描述了。至於Demo,仔細看過官方Demo的哥們都應該看出來了,我的程式碼後面有時間上傳吧。

14.後續遇到的坑

1.最近遇到一個專案中的Bug,百度地圖不能拖動的問題,最後主要原因是當activityA有BaiduMap,並且正在定位,那麼開啟activityB,B中的BaiduMap就會出現過一段時間不能拖動的問題,具體解決就是在生命週期中暫停定位。業務上的需求進行轉移。
2.最近接觸了百度地圖的動畫,也就是官方介紹的生長動畫,新增mark時會以變大的形式出現,這時經理拿著高德,給我看動畫是從一個小圖片直接生長成大圖片,而百度地圖卻只是從中心變大。就坑了,只能多加點程式碼了。
3.最近接觸了FragmentTabHost+Fragment+BaiduMap,切換遇到黑屏問題,後來找了解決方案使用了TextureMapView替換了MapView,就好用了。