1. 程式人生 > >Android進階:步驟四:Android 接入百度地圖API 基礎實現

Android進階:步驟四:Android 接入百度地圖API 基礎實現

內容概括:

  1. 註冊申請百度地圖開發平臺賬號 這裡是地址  如何申請百度地圖的賬號也有官方文件:在這裡
  2. 申請祕鑰(AK)、快速獲取釋出版SHA1和測試版SHA1和包名
  3. (文件裡面也有如果建立應用以及申請的教程,但在Android Studio中實現更加簡單)
  4. 百度地圖的Android Studio的配置
  5. app上實現百度地圖的基礎功能
  6. app實現切換百度地圖的型別(基本和衛星地圖)
  7. 實現定位功能
  8. 顯示附近商家

一、建立接入百度地圖的應用 這裡是連結 必須先註冊驗證成功

1.下面建立應用的介面

2.應用名稱隨意:我這裡填寫baiduMap

3.我們選擇應用型別為Android SDK 

4.啟動服務預設全選就好

5.釋出版SHA1和測試版SHA1是什麼?怎麼簡單獲取這才是重點

也就是所謂的debug版本和release版本的數字簽名,這裡不做過多解析,一種加密演算法來保證app安全的。

怎麼簡單獲取應用的釋出版SHA1和測試版SHA1?

我們開啟Android Studio新建一個工程(命名為BaiduMapDemo)

注意紅色框框內就是我們這個應用的包名可以修改:我這裡寫的是

包名:com.demo.baidumap

其他設定預設,建立成功。 

建立好工程後,我們找到Gradle Scripts

1.點選工程下的build.gradle

2.點選螢幕右邊隱藏一個側邊區域(Gradle)

3.如果點選後出現的是空白頁面點選,藍色按鈕就會出現了

4.那麼找到,android包下的signingReport 雙擊(雙擊)

雙擊後再AS的下面Run介面 就會出現

5.我們要的測試版(debug)的SHA1在這裡了

這個就是測試版的SHA1:

SHA1: DA:6C:6E:D6:09:98:8B:7D:1C:93:47:03:EC:C2........省略

----------
Variant: debug
Config: debug
Store: /Users/mac/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 91:83:72:3C:C4:74:5A:8D:99:28:59:BE:90:A0:10:C8
SHA1: DA:6C:6E:D6:09:98:8B:7D:1C:93:47:03:EC:C2........省略
Valid until: 2048年3月1日 星期日
----------

6、怎麼獲取釋出版的SHA1

1.Build——>Generate Singed APK

2.預設app即可,next

3.點選create new... 

4.第一個是你存放檔案的路徑,注意: 字尾名是.keystore (因為它要生成一個.keystore的檔案)

password 自定 我這裡是android 所有都設定成了android 要記下這個密碼,下面的填寫任意

填寫完成點選OK

 

不需要點選next,這時候你存放的路徑就有一個.keystore檔案了

6.拿到.keystore檔案後,開啟終端 

複製這行命令:

keytool -list -v -keystore 

空一個格,將你的.keystore檔案拉進終端,就會自動識別它所在的路徑

enter鍵,後提示輸入輸入金鑰庫口令:  就是上面那個密碼 我這裡是android

7.輸入密碼之後,就會出現釋出版的SHA1了

這裡我們兩個SHA1都拿到了

返回百度地圖開發平臺的應用建立介面

填寫相應的SHA1即可,注意包名千萬不能寫錯,SHA1也是,錯了就無法用到百度地圖sdk了,注意檢查上面是否有遺漏步驟

提交後,你就有一個訪問應用的AK了,接下來配置有用 

二、百度地圖的Android Studio的配置

1.下載百度地圖sdk的jar包這裡是地址 在產品下載

這裡我們選擇自定義下載 我們選擇了 你可以全部選擇,因為接下來的實現效果只用上這麼多所有我們選擇了3個基礎功能

  1. 基礎定位
  2. 基礎地圖
  3. 計算工具

下載開發包和示例程式碼和類參考,如要進行深入開發,可以看他的demo

下載完成後解壓

這裡是百度地圖官方的Android Studio配置文件

看不懂我的操作的,可以看看官方的配置文件

1.拷貝BaiduLBS_Android.jar(我們所需要的jar包在⁨BaiduLBS_AndroidSDK_Lib⁩ ▸ ⁨libs⁩裡面)放到工程app/libs目錄下

找不到libs目錄?你可能隱藏了雙擊上面就會顯示出來了

2.在src/main/目錄下新建jniLibs目錄,並把 armeabi目錄和x86目錄載入到jniLibs目錄中

注意:

這裡我只放了armeabi和x86的兩個平臺的包,而官方建議是放所有的平臺,也就是4個,但是每一個體積有4M多,放入更多就會使app的體積變大,所以這裡放2個,接下來的操作都是文件裡不涉及的,是為了解決放2個而導致的問題的

放四個可以參考官方文件:

 

這裡是百度地圖官方的Android Studio配置文件

 3.新增配置解決2個平臺引入新的問題

1.開啟module的build.gradle

在defaultConfig模組中新增一個ndk模組 如下(目的保證所有的應用只生成兩個平臺的,不生成其他平臺的so不加會導致奔潰)

   compileSdkVersion 27
    defaultConfig {
        applicationId "com.demo.baidumap"
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        
        ndk{
            abiFilters 'armeabi','x86'
        }
   
    }

 2.新增jar檔案的依賴 同樣是在build.gradle,中

dependencies模組中新增依賴   :implementation files('libs/BaiduLBS_Android.jar') 然後同步一下
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation files('libs/BaiduLBS_Android.jar')
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

3.應用混淆

整合地圖SDK的應用,在打包混淆的時候,需要注意與地圖SDK相關的方法不可被混淆。混淆方法如下:

-keep class com.baidu.** {*;}
-keep class mapsdkvi.com.** {*;}    
-dontwarn com.baidu.**

注意:保證百度類不能被混淆,否則會出現網路不可用等執行時異常

複製上面的程式碼,開啟proguard-rules.pro

然後貼上到末尾,貼上進去其實並沒有生效

接下來,在來到build.gradle裡面開啟混淆配置

在buildTypes模組中(這是初始的樣子)

  buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

修改後 開啟混淆配置為true

 buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

之後還有在build.gradle模組中配置我們剛剛上面的keystore檔案

1.將.keystore檔案拷貝到module目錄下

做如下配置:新建signingConfigs模組,並且在buildTypes中引入

下面的keyAlias和密碼是你建立.keystore寫的

   signingConfigs{
        releaseConfig{
            storeFile file('baidumap.keystore')
            storePassword 'android'
            keyAlias 'android'
            keyPassword 'android'
        }
        
    }
    buildTypes {
        release {
            minifyEnabled true
            signingConfig signingConfigs.releaseConfig
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

注意: 此時可以通過點選右邊Gradle,雙擊工程的android目錄下signingReport,就獲取到release和debug兩個的SHA1,檢查一下是否和在百度地圖開發平臺寫的一致,我檢查了一遍,發現開發版SHA1的不一致,以signingReport出來的為準.(切記,還有包名不要寫錯)

包名在build的defaultConfig模組也可以看到:applicationId "com.demo.baidumap"

1.開發版SHA1

2.測試版SHA1

3.包名

三者確保沒有寫錯!

三、 app上實現百度地圖的基礎功能

1.在module的AndroidManifest.xml配置

(1)在application中新增開發金鑰(AK)

示例: 

<application>  
    .....
    <meta-data  
        android:name="com.baidu.lbsapi.API_KEY"  
        android:value="開發者 key" />  
......
</application>

開發者Key是建立應用完成後的訪問應用的AK

(2)新增所需許可權

注意: 許可權應新增在 appliction 之外,如新增到appliction 內部,會導致無法訪問網路,不顯示地圖。

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--獲取裝置網路狀態,禁用後無法獲取網路狀態-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--網路許可權,當禁用後,無法進行檢索等相關業務-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!--讀取裝置硬體資訊,統計資料-->
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <!--讀取系統資訊,包含系統版本等資訊,用作統計-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--獲取裝置的網路狀態,鑑權所需網路代理-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--允許sd卡寫許可權,需寫入地圖資料,禁用後無法顯示地圖-->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <!--獲取統計資料-->
    <uses-permission android:name="android.permission.CAMERA" />
    <!--使用步行AR導航,配置Camera許可權-->

(3) 在佈局xml檔案中新增地圖控制元件;

acitivity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".MainActivity">

    <com.baidu.mapapi.map.MapView
        android:id="@+id/id_baidumap"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true" />

</LinearLayout>

(4)新建一個BaiduMapApplication類繼承Application 在oncreate方法中寫如下:

  • 注意:在SDK各功能元件使用之前都需要呼叫
  • SDKInitializer.initialize(getApplicationContext());,因此我們建議該方法放在Application的初始化方法中
public class BaiduMapApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //在使用SDK各元件之前初始化context資訊,傳入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地圖SDK所有介面均支援百度座標和國測局座標,用此方法設定您使用的座標型別.
        //包括BD09LL和GCJ02兩種座標,預設是BD09LL座標。
        SDKInitializer.setCoordType(CoordType.BD09LL);
    }
}

然後到AndroidManifest.xml更改我們的Application (別忘了)

       加入: android:name=".BaiduMapApplication"


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:name=".BaiduMapApplication"
        android:theme="@style/AppTheme">

(5) 建立地圖BaiduMapActivity,管理地圖生命週期;

public class BaiduMapActivity extends AppCompatActivity {

    private MapView mMapView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //獲取地圖控制元件引用
        mMapView = findViewById(R.id.bmapView);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在activity執行onDestroy時執行mMapView.onDestroy(),實現地圖生命週期管理
        mMapView.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //在activity執行onResume時執行mMapView. onResume (),實現地圖生命週期管理
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //在activity執行onPause時執行mMapView. onPause (),實現地圖生命週期管理
        mMapView.onPause();
    }
}

 完成以上步驟後(開啟失敗,請仔細檢查是否遺漏哪些步驟),執行程式,即可在您的應用中顯示地圖。 

如果沒有遺漏,請檢查你的釋出版SHA1 和測試版SHA1

(點選Gradle—>android—>雙擊signingReport在run插入 release和debug的SHA1是否和百度地圖建立應用填寫的一致)

和包名是否寫錯

四、調通示例百度Map的Demo

我們下載了BaiduLBS_AndroidSDK_Sample.zip 官方的示例demo

解壓後我們把BaiduLoc_AndroidSDK_v7.5_Demo包中Studio版本的BaiduLocDemo的app檔案(此時是一個module)匯入到我們的工程中

File——>New——>import Module——>選擇要匯入的module

匯入之後,會提示一些錯誤,比如版本不匹配,或者是compile 要修改成implementation

執行之後你還有可能出現

 Failed to extract native libraries, res=-113的錯誤

意味著你的模擬器不支援,可以新建一個arm平臺的模擬器(不建議非常慢),當然用真機更好

MAC 版android studio 真機除錯

注意,版本大於23之後要動態新增許可權

五、app實現切換百度地圖的型別(基本和衛星地圖)

參考百度地圖官方切換地圖的文件

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapView;

public class BaiduMapActivity extends AppCompatActivity {

    public static final int ITEM_ID_NORMAL_MAP = 101;
    public static final int ITEM_ID_SATELLITE = 102;
    public static final int ITEM_ID_TIME = 103;
    public static final int ITEM_ID_HOT = 104;
    private MapView mMapView = null;
    private BaiduMap mBaiduMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //獲取地圖控制元件引用
        mMapView = findViewById(R.id.bmapView);
        //拿到map物件
        mBaiduMap = mMapView.getMap();
    }

    /**
     * 建立新增選單
     *
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, ITEM_ID_NORMAL_MAP, 0, "切換成普通地圖");
        menu.add(Menu.NONE, ITEM_ID_SATELLITE, 0, "切換成衛星地圖");
        menu.add(Menu.NONE, ITEM_ID_TIME, 0, "切換成實時路況圖地圖");
        menu.add(Menu.NONE, ITEM_ID_HOT, 0, "切換成城市熱力地圖");
        return super.onCreateOptionsMenu(menu);
    }

    /**
     * 選單點選事件
     *
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case ITEM_ID_NORMAL_MAP:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
                mBaiduMap.setTrafficEnabled(false);
                mBaiduMap.setBaiduHeatMapEnabled(false);
                break;
            case ITEM_ID_SATELLITE:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
                mBaiduMap.setTrafficEnabled(false);
                mBaiduMap.setBaiduHeatMapEnabled(false);

                break;
            case ITEM_ID_TIME:
                mBaiduMap.setTrafficEnabled(true);
                mBaiduMap.setBaiduHeatMapEnabled(false);
                break;
            case ITEM_ID_HOT:
                mBaiduMap.setBaiduHeatMapEnabled(true);
                mBaiduMap.setTrafficEnabled(false);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在activity執行onDestroy時執行mMapView.onDestroy(),實現地圖生命週期管理
        mMapView.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //在activity執行onResume時執行mMapView. onResume (),實現地圖生命週期管理
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //在activity執行onPause時執行mMapView. onPause (),實現地圖生命週期管理
        mMapView.onPause();
    }
}

效果: 

六、實現定位功能

參考官方定位文件

1.定位SDK的配置

(1)AndroidManifest.xml中新增定位許可權

 

 

1.使用定位SDK,需在Application標籤中宣告service元件,每個App擁有自己單獨的定位service,程式碼如下:

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

2. 除新增service元件外,使用定位SDK還需新增如下許可權:(注意許可權可能和上方之前的有些重複,要去掉)

<!-- 這個許可權用於進行網路定位-->
<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>
<!-- 寫入擴充套件儲存,向擴充套件卡寫入資料,用於寫入離線定位資料-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 訪問網路,網路定位需要上網-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡讀取許可權,使用者寫入離線定位資料-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

 

2.初始化LocationClient類

import android.content.Context;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

/**
 * 實現獲取定位資訊返回給我們的主Activity
 */
public class LocationInstance {
    /**
     * 第一步:初始化LocationClient類
     */
    public LocationClient mLocationClient;
    private MyLocationListener myListener;

    //BDAbstractLocationListener為7.2版本新增的Abstract型別的監聽介面
//原有BDLocationListener介面暫時同步保留。具體介紹請參考後文第四步的說明
    public LocationInstance(Context context, MyLocationListener myListener) {
        mLocationClient = new LocationClient(context);
        //宣告LocationClient類
        mLocationClient.registerLocationListener(myListener);
        //註冊監聽函式

        /**
         * 第二步:配置定位SDK引數
         */
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        option.setCoorType("bd09ll");
        option.setScanSpan(1000);
        option.setOpenGps(true);
        option.setLocationNotify(true);
        option.setIgnoreKillProcess(false);
        option.SetIgnoreCacheException(false);
        option.setWifiCacheTimeOut(5 * 60 * 1000);
        option.setEnableSimulateGps(false);
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

    /**
     * 第三步.實現BDAbstractLocationListener介面
     */
    public static class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            //此處的BDLocation為定位結果資訊類,通過它的各種get方法可獲取定位相關的全部結果
            //以下只列舉部分獲取經緯度相關(常用)的結果資訊
            //更多結果資訊獲取說明,請參照類參考中BDLocation類中的說明

            double latitude = location.getLatitude();    //獲取緯度資訊
            double longitude = location.getLongitude();    //獲取經度資訊
            float radius = location.getRadius();    //獲取定位精度,預設值為0.0f

            String coorType = location.getCoorType();
            //獲取經緯度座標型別,以LocationClientOption中設定過的座標型別為準

            int errorCode = location.getLocType();
            //獲取定位型別、定位錯誤返回碼,具體資訊可參照類參考中BDLocation類中的說明
        }
    }

    /**
     * 第四步:設定定位的開始和結束的方法
     * 1s定位一次非常耗電的操作
     */
    public void start() {
        mLocationClient.start();
    }

    public void stop() {
        mLocationClient.stop();
    }


}

3.在主介面中拿到例項 

    private LocationInstance mLocationInstance;
    private BDLocation lastLocation;//存放最新一次的位置
....


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        .....
        //初始化定位
        initLocation();
    }
 /**
     * 初始化定位獲取例項的方法
     */
    private void initLocation() {
        mLocationInstance = new LocationInstance(
                this,
                new LocationInstance.MyLocationListener() {
                    @Override
                    public void onReceiveLocation(BDLocation location) {
                        super.onReceiveLocation(location);
                        //在這裡拿到返回的Location的資訊
                        lastLocation=location;
                        Log.d("MAP",
                                location.getAddrStr()+","+"" +
                                        location.getLatitude()+","+
                                        location.getLongitude());
                    }
                });
    }

    /**
     * 開啟Location
     */
    @Override
    protected void onStart() {
        mLocationInstance.start();
        super.onStart();
    }

    /**
     * 關閉Location
     */
    @Override
    protected void onStop() {
        mLocationInstance.stop();
        super.onStop();
    }

 4.動態申請許可權

此時執行程式,如果是android6.0 sdk23之前都可以顯示定位資訊

但是:android6.0之後一些許可權需要動態申請才行

所有寫一個SplashActivity在沒進入主介面的時候來獲取許可權,如果必要的許可權沒有獲取到

就退出應用,並提升使用者還有哪些許可權沒獲取;

下次開啟之後,只要獲取未獲取的許可權即可,不用重新再獲取一遍

參考這篇文章:android6.0之後動態獲取許可權的封裝

列印結果 

com.demo.baidumap D/MAP: 中國湖北省武漢市******,30.501075,114.402673
com.demo.baidumap D/MAP: 中國湖北省武漢市******,30.501075,114.402673
com.demo.baidumap D/MAP: 中國湖北省武漢市******,30.501075,114.402673

3.將定位功能引入我們介面中去:

 顯示自己的定位並繪製一個點標記:官方參考文件

   case ITEM_LOCATION:
                //當點選我的定位之後會定位到我的位置,並出現一個方向圖片
                mBaiduMap.clear();//每次點選不清除就會疊加
                //定義Maker座標點(獲取經緯度)
                LatLng point = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
                //構建Marker圖示

                BitmapDescriptor bitmap = BitmapDescriptorFactory
                        .fromResource(R.drawable.navi_map_gps_locked);
                //構建MarkerOption,用於在地圖上新增Marker

                OverlayOptions option = new MarkerOptions()
                        .position(point)
                        .icon(bitmap);
                //在地圖上新增Marker,並顯示

                mBaiduMap.addOverlay(option);

                //地圖可以移動到中心點過去

mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));

                break;

改變地圖手勢的中心點(地圖的中心點)

改變地圖手勢的中心點,即需要改變地圖的中心點,手勢旋轉等操作是以地圖中心點 做旋轉的。

在上面的程式碼最後加上:

mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));

修改預設的縮放級別,在oncreate中新增

        mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15f));

 

這是使用Vysor同手機螢幕在電腦上

旋轉手機可以使定位箭頭隨感測器移動而移動:

參考文件:顯示定位文件

1.寫一個感測器類:SensorInstantce.java

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

/**
 * 這是感測器的一個類
 * 傳出x
 * 設定位置指標的走向
 */
public class SensorInstantce implements SensorEventListener {
    private Context mContext;
    SensorManager mSensorManager;

    public SensorInstantce(Context mContext) {
        this.mContext = mContext;
    }

    public void start() {
        //開啟感測器服務
        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager != null) {//防止有些手機不支援
            //拿到sensor物件,方向感測器
            Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
            if (sensor != null) {
                mSensorManager.registerListener((SensorEventListener) this, sensor, SensorManager.SENSOR_DELAY_UI);
            }
        }
    }

    public void stop() {
        //停止服務
        mSensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {
            float x = sensorEvent.values[SensorManager.DATA_X];
            if (mListener != null) {
                //把x傳出去
                mListener.onOrientation(x);
            }
        }

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

    /***
     * OnOrientationChangedListener 利用這個方法來將實時改變的x傳出去
     */

    private OnOrientationChangedListener mListener;

    public void setOnOrientationChangedListener(OnOrientationChangedListener listener) {
        mListener = listener;
    }

    public static interface OnOrientationChangedListener {
        void onOrientation(float x);
    }
}

2.在BaiduMapAcitivity中

(1)新增成員變數

mIsFirstLocation來實現,第一次如果有定位就直接定位到你當前的定位了

    private SensorInstantce mSensorInstance;//方向感測器物件
    private boolean mIsFirstLocation = true;

(2)oncreate方法中初始化

     mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15f));

        //初始化定位
        initLocation();
        //初始化方向感測器
        initSensorInstance();
        // 開啟定點陣圖層
        mBaiduMap.setMyLocationEnabled(true);

這是初始化感測器的方法

 /**
     * 初始化方向感測器,控制定位指標的隨感測器的移動而改變
     * 手機移動到哪,圖示就指哪個方向
     */
    private void initSensorInstance() {
        mSensorInstance = new SensorInstantce(getApplicationContext());
        mSensorInstance.setOnOrientationChangedListener(new SensorInstantce.OnOrientationChangedListener() {
            @Override
            public void onOrientation(float x) {
                //設定定點陣圖標
                if (lastLocation == null) {//如果上次沒有定位,則不需要改變
                    return;
                }
                //實現定位功能
                // 構造定位資料
                MyLocationData locData = new MyLocationData.Builder()
                        .accuracy(lastLocation.getRadius())
                        // 此處設定開發者獲取到的方向資訊,順時針0-360
                        .direction(x).latitude(lastLocation.getLatitude())
                        .longitude(lastLocation.getLongitude()).build();

                // 設定定位資料
                mBaiduMap.setMyLocationData(locData);

                // 設定自定義定點陣圖層的配置(定位模式,是否允許方向資訊,使用者自定義定點陣圖標)
//                BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory
//                        .fromResource(R.drawable.navi_map_gps_locked);
                //不需要自定義圖示
                MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,
                        true, null);
                mBaiduMap.setMyLocationConfiguration(config);

                /**
                 * 實現以進入地圖就定位到我們的位置
                 */
                if (mIsFirstLocation) {
                    mIsFirstLocation = false;
                    //拿到位置
                    LatLng point = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
                    mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));
                }

            }
        });
    }

(3)同樣要在Acitivity的onstart 和onStop中開啟、關閉 

 /**
     * 開啟Location和感測器
     */
    @Override
    protected void onStart() {
        mLocationInstance.start();
        mSensorInstance.start();
        super.onStart();
    }

    /**
     * 關閉Location和感測器
     */
    @Override
    protected void onStop() {
        mLocationInstance.stop();
        mSensorInstance.stop();
        super.onStop();
    }

最後如果出現了兩個圖示

在定位的選單的點選事件中,除掉一個圖示

            case ITEM_LOCATION:
            。。。。。
                //在地圖上新增Marker,並顯示
                //將下面那一個圖示去掉

//                mBaiduMap.addOverlay(option);

指標方向隨手機移動方向改變

 

 

 七、實現新增附件商家的Marker

百度地圖拾取座標系統的查詢

通過拿到的經緯度查詢座標

com.demo.baidumap D/MAP: 中國湖北省武漢市******,30.501075,114.402673(緯度,經度)

longtitute:經度 

Latitude:緯度

 第一:給商家資訊做一個分裝類

AddressInfo.java

/**
 * 附件商家資訊的封裝
 */
public class AddressInfo {
    private double latitude;//經度
    private double longtitude;//緯度
    private int imgId;//圖片
    private String name;//名稱
    private String distance;//距離

    public AddressInfo() {
    }

    public AddressInfo(double latitude, double longtitude, int imgId, String name, String distance) {
        this.latitude = latitude;
        this.longtitude = longtitude;
        this.imgId = imgId;
        this.name = name;
        this.distance = distance;
    }

    public double getLatitude() {
        return latitude;
    }

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

    public double getLongtitude() {
        return longtitude;
    }

    public void setLongtitude(double longtitude) {
        this.longtitude = longtitude;
    }

    public int getImgId() {
        return imgId;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDistance() {
        return distance;
    }

    public void setDistance(String distance) {
        this.distance = distance;
    }
}

第二:拿到所有商家資訊的集合類


/**
 * 商家資料類
 */
public class AddressInfoLab {

    public static List<AddressInfo> generateDatas() {

        List<AddressInfo> addressInfos = new ArrayList<>();
        // http://api.map.baidu.com/lbsapi/getpoint/index.html
        addressInfos.add(new AddressInfo(30.499861, 114.405871, R.drawable.a1, "關山荷蘭風情園",
                "距離209米"));
        addressInfos.add(new AddressInfo(30.50288, 114.402457, R.drawable.a2, "長江職業學院",
                "距離897米"));
        addressInfos.add(new AddressInfo(30.500655, 114.40005, R.drawable.a3, "天龍公寓",
                "距離249米"));
        addressInfos.add(new AddressInfo(30.501277, 114.403679, R.drawable.a4, "三福",
                "距離679米"));
        return addressInfos;
    }
}

第三:在主介面中新增附件商家的選單按鈕

   case ITEM_SHOWSHOP:
                //遍歷商家,新增marker
                showShops();
                break;

具體的商家顯示的方法: 


    /**
     * 顯示商家的方法,並新增marker
     */
    private void showShops() {
        mBaiduMap.clear();//每次點選不清除就會疊加
        //拿到商家資訊
        List<AddressInfo> addressInfoList = AddressInfoLab.generateDatas();
        for (AddressInfo addressInfo : addressInfoList) {
            //定義Maker座標點(獲取經緯度)
            LatLng point = new LatLng(addressInfo.getLatitude(), addressInfo.getLongtitude());
            //構建Marker圖示
            BitmapDescriptor bitmap = BitmapDescriptorFactory
                    .fromResource(R.drawable.maker);
            //構建MarkerOption,用於在地圖上新增Marker

            OverlayOptions option = new MarkerOptions()
                    .position(point)
                    .icon(bitmap);
            //在地圖上新增Marker,並顯示
            mBaiduMap.addOverlay(option);
        }
        //如果沒有地址直接返回
        if (addressInfoList.isEmpty()) {
            return;
        }
        LatLng point = new LatLng(addressInfoList.get(0).getLatitude()
                , addressInfoList.get(0).getLongtitude());

        //讓地圖自動移動到第一個商家的位置
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));
    }

 

接下來要處理兩個事件

  • 1.商家marker的點選事件
  • 2.點選之後顯示商家資訊

1.點選事件會彈出一個View

所以建一個佈局 item_address_info.xml 用來顯示點選商家的資訊

<?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="wrap_content"
    android:background="#cc4e5a6b">

    <ImageView
        android:id="@+id/id_marker_img"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_margin="12dp"
        android:background="@drawable/bg_img_icon"
        android:scaleType="fitXY"
        android:src="@drawable/a1" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/id_marker_img"
        android:layout_marginBottom="6dp"
        android:layout_marginEnd="6dp"
        android:layout_marginStart="6dp"
        android:background="#4d5c6c">

        <TextView
            android:id="@+id/id_tx_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14dp"
            tools:text="關山風情園" />

        <TextView
            android:id="@+id/id_tx_distance"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:textSize="14dp"
            tools:text="關山風情園" />
    </FrameLayout>


</RelativeLayout>

2.為了讓主介面不那麼顯得容易,單獨建個類來實現View的展示

AddressView.java 商家資訊顯示的View類

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.demo.baidumap.R;
import com.demo.baidumap.bean.AddressInfo;


/**
 * marker詳情佈局
 */

public class AddressView extends RelativeLayout {
    private ImageView mIvIcon;
    private TextView mTvName;
    private TextView mTvDistance;


    public AddressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setVisibility(View.GONE);
        LayoutInflater
                .from(context)
                .inflate(
                        R.layout.item_address_info,
                        this);
        mIvIcon = findViewById(R.id.id_marker_img);
        mTvName = findViewById(R.id.id_tx_name);
        mTvDistance = findViewById(R.id.id_tx_distance);

    }

    //對外接受商家資訊
    public void setAddressInfo(AddressInfo info) {
        mIvIcon.setImageResource(info.getImgId());
        mTvName.setText(info.getName());
        mTvDistance.setText(info.getDistance());
        setVisibility(View.VISIBLE);
    }
}

3.在主Activity中

1.宣告檢視物件

   //宣告佈局物件
 private AddressView mAddressView;

2.oncreate中初始化檢視 和點選事件

 //底部商家詳情頁
        mAddressView = findViewById(R.id.id_address_view);
   //初始化點選事件
        initEvent();

3.點選事件(點選marker和點選地圖)兩個事件


    public static final String SHOW_INFO = "showInfo";
    private void initEvent() {

        /**
         * 商家marker的點選事件
         */
        mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {

            @Override
            public boolean onMarkerClick(Marker marker) {
                //點選marker之後拿到marker傳來的額外資訊
                Bundle extraInfo = marker.getExtraInfo();
                AddressInfo addressInfo = (AddressInfo) extraInfo.getSerializable(SHOW_INFO);
                //點選某個marker之後
                mAddressView.setAddressInfo(addressInfo);
                Log.d("TAG", addressInfo.getName());
                //show view
                return false;
            }
        });

        /**
         * 點選地圖的事件(讓商家資訊消失)
         */
        mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                mAddressView.setVisibility(View.GONE);
            }

            @Override
            public boolean onMapPoiClick(MapPoi mapPoi) {
                return false;
            }
        });
    }

在顯示商家的方法中將商家的位置放進bundle等待點選事件的觸發(獲取商家額外資訊extraInfo)

  /**
     * 顯示商家的方法,並新增marker
     */
    private void showShops() {
    .......
            //構建Marker圖示
            BitmapDescriptor bitmap = BitmapDescriptorFactory
                    .fromResource(R.drawable.maker);

            /**
             * 拿到額外資訊存到extraInfo裡面
             */
            Bundle bundle = new Bundle();
            bundle.putSerializable(SHOW_INFO, addressInfo);
            //並傳進去
            //構建MarkerOption,用於在地圖上新增Marker
            OverlayOptions option = new MarkerOptions()
                    .position(point)
                    .extraInfo(bundle)//將bundle傳進去
                    .icon(bitmap);
         ........
    }

最後還有在顯示商家的方法中GONE掉檢視

  case ITEM_SHOWSHOP:
                //點選mark gone掉
                mAddressView.setVisibility(View.GONE);
                //遍歷商家,新增marker
                showShops();
                break;

最終效果: 

參考:百度地圖開發者文件、和幫助與反饋、還有demo來學習百度地圖的SDK