說說在 Android 如何實現基於位置的服務(基於百度 API)

基於位置的服務簡稱 LBS(Location Based Service),它是利用無線電通信網絡或 GPS 定位方式來肯定出移動設備所在的位置。android

利用定位服務,能夠開發出許多豐富多彩的功能。好比天氣預報 APP,能夠根據用戶所在的位置自動選擇所在城市。約會時,能夠經過微信發出碰頭地點,讓朋友們可以儘快過來等等。git

肯定出用戶所在的位置。一般有兩種技術:api

技術 說明 優勢 不足
GPS 定位 它是基於手機內置的 GPS 硬件直接和衛星交互來得到當前的經緯度信息。 精確度高 只能室外使用,由於室內基本沒法接收到衛星的信號。
網絡定位 根據手機當前網絡附近的三個基站進行測速,以此計算出手機和每一個基站之間的距離,最後經過三角定位肯定一個大概位置。 室內外都可使用。 精確度通常。

2 申請百度 API Key

首先必須先註冊一個百度開發者帳號(官網請點擊),這個很簡單,因此這裏就不贅述了哦O(∩_∩)O哈哈~數組

註冊並登錄成功後,打開百度地圖開放平臺建立新應用:安全

  • 應用類型選擇:Android SDK。
  • 啓用服務中選擇 Android 定位 SDK與 Android地圖SDK,默認爲全選。
  • 發佈版與開發版 SHA1:使用 Android Studio 的 Gradle 插件生成的結果。
  • 包名:就是項目所在的包路徑。

點擊 Android Studio 的 Gradle 標籤,執行 signingReport 任務。bash

執行成功後,點擊右下角的【Gradle Console】標籤,能夠看到生成的 SHA1 碼:微信


點擊【提交】成功後,就會轉到應用列表頁,裏面的訪問應用(AK)就是咱們申請到的 API Key 啦:網絡

3 實現定位服務

建議在手機上運行下面的代碼,由於這樣能夠獲得真實的位置數據,有助於咱們更深入地理解基於位置的服務。app

3.1 下載並安裝百度 API 包

打開百度地圖開放平臺,找到地圖引擎入口:ide

點擊後,進入地圖 SDK 說明頁:

點擊產品下載-》自定義下載,在此選擇相應的開發資源:

這裏咱們選擇【全量定位】與【基礎地圖】資源。

  • 全量定位:包含離線定位、室內高精度定位能力,同時提供更人性化的位置描述服務。
  • 基礎地圖:包括基礎地圖、衛星圖、路況圖和各類覆蓋物,及與地圖相關的操做、事件監聽。

這裏的 BaiduLBS_Android.jar 就是百度提供的 API 包。因此咱們把這個包放入 app 的 libs 目錄下:

**注意:**若是找不到 libs 目錄,一個可能的緣由是視圖模式問題,視圖模式(頁籤左上角)請選擇【Project】。

接下來在 app → src → main 中,新建一個 jniLibs 文件夾,而後再把百度下載包中的其它文件夾都拷貝到這個新建的文件夾中:

由於是手動引入包,因此須要點擊 Android Studio 工具欄中的 Sync Project with Gradle Files,手動同步:

同步成功後,就會發現剛纔手工引入的 jar 包左側多了一個朝右的箭頭,這就表示這個包在項目中能夠引用啦:

3.2 顯示當前位置經緯度

3.2.1 佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/position"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</LinearLayout>

複製代碼

這裏,咱們使用 TextView 來顯示當前位置的經緯度。

3.2.2 AndroidManifest.xml

...
<!--百度 LBS API 的相關權限聲明-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

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

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

	<activity android:name=".MainActivity">
		<intent-filter>
			<action android:name="android.intent.action.MAIN" />

			<category android:name="android.intent.category.LAUNCHER" />
		</intent-filter>
	</activity>

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

複製代碼

在此,咱們作了如下工做:

  1. 添加百度 LBS API 須要用到的相關權限聲明。
  2. <application> 標籤內添加了 <meta-data> 標籤,在此記錄以前申請的百度 API Key。
  3. 最後註冊百度 LBS 服務。之因此服務名叫 f,是由於代碼被混淆過。

3.2.3 活動類

public class MainActivity extends AppCompatActivity {

    public static final int REQUEST_CODE = 1;


    public LocationClient locationClient;

    private TextView position;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        locationClient = new LocationClient(getApplicationContext());
        //註冊【定位監聽器】
        locationClient.registerLocationListener(new LocationListener());

        position = (TextView) findViewById(R.id.position);

        /**
         * 一次性申請多個權限
         */
        List<String> permissions = new ArrayList<>();
        addPermission(permissions, Manifest.permission.ACCESS_FINE_LOCATION);
        addPermission(permissions, Manifest.permission.READ_PHONE_STATE);
        addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (!permissions.isEmpty()) {
            ActivityCompat.requestPermissions(MainActivity.this, permissions.toArray(new String[permissions.size()]), REQUEST_CODE);
        } else {
            beginLocation();
        }
    }

    /**
     * 開始定位
     */
    private void beginLocation() {
        setLocationOptions();
        locationClient.start();
    }

    /**
     * 設置 LBS
     */
    private void setLocationOptions() {
        LocationClientOption option = new LocationClientOption();
        //每 10 s 更新一次當前位置
        option.setScanSpan(10000);
        locationClient.setLocOption(option);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        locationClient.stop();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "權限被拒絕啦", Toast.LENGTH_SHORT).show();
                            finish();
                            return;
                        }
                    }
                    beginLocation();
                } else {
                    Toast.makeText(this, "出現與權限相關的問題啦", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    /**
     * 添加權限
     *
     * @param permissions
     * @param neededPermission 須要的權限
     */
    private void addPermission(List<String> permissions, String neededPermission) {
        if (ContextCompat.checkSelfPermission(MainActivity.this, neededPermission) != PackageManager.PERMISSION_GRANTED) {
            permissions.add(neededPermission);
        }
    }

    /**
     * 定位監聽器
     */
    private class LocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            StringBuilder content = new StringBuilder();
            content.append("緯度:").append(location.getLatitude() + "\n");
            content.append("經度:").append(location.getLongitude() + "\n");
            content.append("定位方式:");
            if (location.getLocType() == BDLocation.TypeGpsLocation) {
                content.append("GPS");
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
                content.append("網絡");
            }
            position.setText(content);
        }
    }


}
複製代碼

在此,咱們作了如下工做:

  1. 在 onCreate 方法中,咱們註冊了定位監聽器 locationClient,這樣當系統獲取到位置信息時,就會回調這個監聽器。
  2. 由於百度 LBS API 須要多個權限,因此咱們利用 List<String> 實現一次性申請多個權限,由於 ActivityCompat.requestPermissions() 接受數組參數,而 List 轉爲數組很容易。
  3. 在 beginLocation 方法中,咱們首先設置 LBS 參數,讓它每 10 s 更新一次當前位置;接着,啓動定位監聽器。
  4. 系統獲取位置信息時,回調到 LocationListener 的 onReceiveLocation 方法。BDLocation 對象存在幾個經常使用的方法:getLatitude() 表示獲取經度,getLongitude() 表示獲取緯度。getLocType() 表示獲取定位的方式。
  5. 注意: 在 onDestroy() 方法中必須調用 locationClient.stop(); 中止定位,不然 locationClient 會默默地在後臺不停地進行定位工做,這會對手機電量產生嚴重影響。

安裝並運行 APP:

3.3 設置定位模式

由於 GPS 定位須要手動開啓,它通常在手機的設置 → 位置信息中。

若是是小米手機,那麼它在 設置 → 更多設置 → 系統安全 → 位置信息中。

能夠看出,定位模式有三種,上訴截圖中對每一種定位模式都作了詳細介紹。

在 LBS SDK 也有三種定位模式與手機的定位模式相匹配:

定位模式 說明
Hight_Accuracy 高精確度(默認模式),會在 GPS 信號正常的狀況下優先使用 GPS 定位,在沒法接收 GPS 信號時用網絡定位 。
Battery_Saving 節電,只會使用網絡定位。
Device_Sensors 設備傳感器,只會使用GPS定位。

**注意:**只有當定位操做真正開始的時候,纔會影響到手機的電量。

也能夠經過 LocationClientOption 的 setLocationMode 方法來指定定位模式:

option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
複製代碼

3.4 獲取地址信息

經過 LocationClientOption 的 setIsNeedAddress 方法,能夠開啓地址信息獲取功能:

option.setIsNeedAddress(true);
複製代碼

而後就能夠在 BDLocation 中獲取到地址信息啦:

content.append("所在國家:").append(location.getCountry() + "\n");
content.append("所在省份:").append(location.getProvince() + "\n");
content.append("所在市:").append(location.getCity() + "\n");
content.append("所在區:").append(location.getDistrict() + "\n");
content.append("所在街道:").append(location.getStreet() + "\n");
複製代碼

**注意:**獲取地址必須使用網絡哦O(∩_∩)O~

4 使用地圖

4.1 展現地圖

如今讓咱們在 APP 中展現地圖吧O(∩_∩)O~

修改佈局文件,加入地圖視圖控件:

<com.baidu.mapapi.map.MapView
	android:id="@+id/mapView"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:clickable="true">
</com.baidu.mapapi.map.MapView>
複製代碼

以前的 TextView 可使用 android:visibility="gone" 將其隱藏。

修改活動類:

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

	/**
	 * 初始化地圖
	 */
	SDKInitializer.initialize(getApplicationContext());
	setContentView(R.layout.activity_main);

	mapView = (MapView) findViewById(R.id.mapView);
	...
}


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

@Override
protected void onDestroy() {
	super.onDestroy();
	locationClient.stop();
	mapView.onDestroy();
}

@Override
protected void onResume() {
	super.onResume();
	mapView.onResume();
}
複製代碼

在該類中,咱們新增了這些邏輯:

  1. 調用 SDKInitializer.initialize() 方法,執行初始化操做。**注意:**必定要在 setContentView(R.layout.activity_main); 以前調用,不然會拋出 you have not supplyed the global app context info from SDKInitializer.initialize(Context) function 錯誤。
  2. 重寫 onResume()、onPause()、onDestroy() 方法,釋放資源。

4.2 移動地圖中心

百度 LBS SDK 的 API 中提供了一個BaiduMap 類,使用如下方法實例化後,就能夠對地圖進行各類各樣的操做啦:

BaiduMap baiduMap = mapView.getMap();
複製代碼

修改活動類:

...
private BaiduMap baiduMap;

//是否爲第一次定位
private boolean isFirstLocated = true;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	...
	baiduMap = mapView.getMap();
}

private class LocationListener implements BDLocationListener {
	@Override
	public void onReceiveLocation(BDLocation location) {

		if (location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
			if (isFirstLocated) {
				LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());

				//設置經緯度
				baiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(latLng));

				//設置縮放級別(在 3 ~ 19 之間)
				baiduMap.animateMapStatus(MapStatusUpdateFactory.zoomTo(16f));
				isFirstLocated = false;
			}
		}
	}
}
複製代碼

能夠看出,經過 LatLng latLng = new LatLng(39.9, 116.3); 方法,就可讓地圖移動任何地址啦O(∩_∩)O~

運行程序:

4.3 標註位置

地圖上能夠添加一個標註,用於顯示當前位置。

百度 LBS SDK 提供了一個 MyLocationData.Builder 類,它封裝了設備當前所在的位置,咱們只需將經緯度信息傳入便可。

修改活動類:

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	...
	baiduMap.setMyLocationEnabled(true);
}
...

private class LocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
        ...
	if (location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
	if (isFirstLocated) {
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());


		//設置經緯度
		baiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(latLng));

		//設置縮放級別(在 3 ~ 19 之間)
		baiduMap.animateMapStatus(MapStatusUpdateFactory.zoomTo(16f));
		isFirstLocated = false;
	}

	//添加標註
	MyLocationData.Builder builder = new MyLocationData.Builder();
	builder.latitude(location.getLatitude());
	builder.longitude(location.getLongitude());
	baiduMap.setMyLocationData(builder.build());
  }
}

@Override
   protected void onDestroy() {
        super.onDestroy();
        locationClient.stop();
        mapView.onDestroy();
        baiduMap.setMyLocationEnabled(false);
    }
複製代碼

作了這些工做:

1.在 onCreate 方法中,開啓標註。 2.在 LocationListener 的 onReceiveLocation 方法中添加標註。 3.在 onDestroy 方法中,關閉標註。

由於通常只需移動一次地圖的中心位置,因此咱們在代碼中加了 isFirstLocated 變量進行判斷。

再次運行:

看見地圖中心的藍點了嗎O(∩_∩)O哈哈~

相關文章
相關標籤/搜索