前言 啦啦啦~各位小伙伴們好~經過這一學期的Android知識的學習,我們學到了很多和Android開發相關的知識,這一學期的學習也要告一段落了。(博客中有很多照片上有代碼,代碼文本較小,各位可按下Ctrl和前滾輪放大後再看~) 一起進入我們今天的相關內容~這次我們將一起學習使用 android 手 ...
前言
啦啦啦~各位小伙伴們好~經過這一學期的Android知識的學習,我們學到了很多和Android開發相關的知識,這一學期的學習也要告一段落了。(博客中有很多照片上有代碼,代碼文本較小,各位可按下Ctrl和前滾輪放大後再看~)
一起進入我們今天的相關內容~這次我們將一起學習使用 android 手機不同的感測器,包括磁強計、加速度感測器等。學會使用 android 位置服務獲得經緯度信息。學會使用百度地圖基礎API進行地圖應用的開發。
基礎知識
一、感測器簡介
手機中內置的感測器是一種微型的物理設備,它能夠探測、感受到外界的信號,並按一定規律轉換成我們所需要的信息。Android 手機通常都會支持多種類型的感測器,如光照感測器、加速度感測器、地磁感測器、壓力感測器、溫度感測器等。
當然,Android 系統只是負責將這些感測器所輸出的信息傳遞給我們,至於具體如何去利用這些信息就要充分發揮開發者的想象力了。
二、Android感測器框架
Android SDK為我們提供了ASF,可以用來訪問當前Android設備內置的感測器。ASF提供了很多類和介面,幫助我們完成各種與感測器有關的任務。例如:
1)確定當前Android設備內置了哪些感測器。
2)確定某一個感測器的技術指標。
3)獲取感測器傳回來的數據,以及定義感測器回傳數據的精度。
4)註冊和註銷感測器事件監聽器,這些監聽器用於監聽感測器的變化,通常從感測器回傳的數據需要利用這些監聽器完成。
ASF允許我們訪問很多感測器類型,這些感測器有一些是基於硬體的感測器,還有一些是基於軟體的感測器。基於硬體的感測器就是直接以晶元形式嵌入到Android設備中,這些感測器直接從外部環境獲取數據。基於軟體的感測器並不是實際的硬體晶元,基於軟體的感測器傳回的數據本質上也來自於基於硬體的感測器,只是這些數據通常會經過二次加工。所以基於軟體的感測器也可以稱為虛擬(virtual)感測器或合成(synthetic)感測器。
Android對每個設備的感測器都進行了抽象,其中SensorManger類用來控制感測器,Sensor用來描述具體的感測器,SensorEventListener用來監聽感測器值的改變。
(1)SensorManager類
用於創建sensor service的實例。該類提供了很多用於訪問和枚舉感測器,註冊和註銷感測器監聽器的方法。而且還提供了與感測器精度、掃描頻率、校正有關的常量。
(2)Sensor類
Sensor類為我們提供了一些用於獲取感測器技術參數的方法。如版本、類型、生產商等。例如所有感測器的TYPE類型如下:
序號 | 感測器 | Sensor類中定義的TYPE常量 |
---|---|---|
1 | 加速度感測器 | TYPE_ACCELEROMETER |
2 | 溫度感測器 | TYPE_AMBIENT_TEMPERATURE |
3 | 陀螺儀感測器 | TYPE_GYROSCOPE |
4 | 光線感測器 | TYPE_LIGHT |
5 | 磁場感測器 | TYPE_MAGNETIC_FIELD |
6 | 壓力感測器 | TYPE_PRESSURE |
7 | 臨近感測器 | TYPE_PROXIMITY |
8 | 濕度感測器 | TYPE_RELATIVE_HUMIDITY |
9 | 方向感測器 | TYPE_ORIENTATION |
10 | 重力感測器 | TYPE_GRAVITY |
11 | 線性加速感測器 | TYPE_LINEAR_ACCELERATION |
12 | 旋轉向量感測器 | TYPE_ROTATION_VECTOR |
註意:1-8是硬體感測器,9是軟體感測器,其中方向感測器的數據來自重力和磁場感測器,10-12是硬體或軟體感測器。
(3)SensorEvent類
系統使用該類創建感測器事件對象。該對象可以提供與感測器事件有關的信息。感測器事件對象包括的信息有原始的感測器回傳數據、感測器類型、數據的精度以及觸發事件的時間。
(4)SensorEventListener介面
該介面包含兩個回調方法,當感測器的回傳值或精度發生變化時,系統會調用這兩個回調方法。
/**
* 感測器精度變化時回調
*/
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
/**
* 感測器數據變化時回調
*/
@Override
public void onSensorChanged(SensorEvent event) {
}
到了這裡,我們就可以進行感測器開發工作了。
實驗內容
本次實驗主要是涉及感測器及地圖相關應⽤,實現簡單的地圖功能。
實現最終結果實現效果如圖所示:
實驗效果圖
主要分為以下三部分
a) 調用百度地圖SDK實現地圖的展示以及交互,其中包括左下角的按鈕要求實現的功能如下:
i. 當按鈕處於狀態時:如果GPS位置有更新,那麼更新用戶當前所在位置,並使得當前位置的箭頭圖標一直保持在屏幕中心。
ii. 按鈕處於 狀態時,更新當前位置的箭頭的時候不移動地圖。
iii. 點擊按鈕可以切換這兩種狀態,當按鈕進入狀態的時候,使得表示當前位置的箭頭位於屏幕中央。
iv. 如果按鈕處於 的狀態手動平移百度地圖的時候,地圖進行平移並且按鈕變為 狀態。
b) 獲取當前所在位置與方向,併在百度地圖上顯示出來,如圖中黑色箭頭所示,箭頭中心位置為定位結果,箭頭方向為手機的朝向。
c) 實現簡單搖一搖功能,當晃動手機的時候作出相應的響應。
實驗過程
1. 首先要申請百度的開發者密鑰(申請密鑰 Android SDK http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key),申請地址:http://lbsyun.baidu.com/apiconsole/key
首先,在申請AK的表單中選擇AndroidSDK,發現還要輸入發佈版SHA1以及報名這兩個信息。
其中,應用包名為build.gradle里的ApplicationId,並且保證這個ApplicationId與Manifest里的package欄位名是一樣的(如下圖所示)。
Manifest 里的應用包名
build.gradle 里的應用包名
發佈版SHA1為了方便直接使用Android預設的debug.keystore里的SHA1,進入用戶文件夾(Windows為C:\Users\username,Linux為/home/username,Mac為/Users/username)後,輸入如下命令即可看到SHA1值(輸入密鑰庫口令里直接回車)
證書指紋里的SHA1值為在申請應用AK的時候需要填寫的。
點擊確定後即可得到一個Android SDK的應用AK:
成功申請應用 AK
下載百度地圖SDK的依賴庫<BaiduLBS_AndroidSDK_Lib.zip>,按照百度地圖SDK配置環境與發佈 (配置環境及發佈 Android SDK :http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject) 把依賴庫放到相應的文件夾並添加到工程里,並按照HelloBaiduMap (Hello BaiduMap:http://lbsyun.baidu.com/index.php?title=androidsdk/guide/hellobaidumap)中的步驟,在AndroidManifest.xml文件里添加許可權以及應用AK。
特別的,由於Android API 23以上需要動態申請許可權,這裡使用一個Github上的開源工具RxAndroid( https://github.com/ReactiveX/RxAndroid)進行處理,也可以自己根據Android官方的API進行或者其他的工具。首先需要在build.gradle中加入需要的依賴項:
然後新建一個啟動的Activity,在這個單獨的Activity的onCreate方法里檢查是否獲取需要的許可權,如果沒有則直接退出程式,實現代碼參考如下:
本次實驗主要涉及使用 android 手機不同的感測器,包括磁強計、加速度感測器等,使用 android 位置服務獲得經緯度信息,使用百度地圖基礎 API 進行地圖應用的開發。
首先按照文檔中的要求申請百度的開發者密鑰,並正確申請 AK(應用包名為build.gradle里的ApplicationId,並且保證這個ApplicationId與Manifest里的 package 欄位名是一樣的):
按照百度地圖 SDK 配置環境與發佈把依賴庫放到相應的文件夾並添加到工程里,並按照 HelloBaiduMap 中的步驟,在 AndroidManifest.xml 文件里添加許可權以及應用 AK:
這裡進行 so 的配置時,在 app 工程路徑下,新建 libs,併在 libs 目錄下放入對應不同 CPU 架構的 so 文件。
這樣工程並不會自動載入 libs 下的 so,需在gradle 編譯時,通過加入代碼:jniLibs.srcDir 'libs' 來說明 so 的路徑為該libs 路徑。代碼如下:
由於 Android API 23 以上需要動態申請許可權,這裡使用開源工具 RxAndroid進行處理(具體方法之前已敘述過,這裡就不再贅述)。
接下來通過使用感測器來獲取手機的方向信息和位置信息。
手機的方向信息是通過地磁感測器和加速度感測器共同計算出來的,需要獲取地磁感測器和加速度感測器的信息(調用手機大多數感測器首先需要獲取感測器的管理器,感測器都需要由這個感測器管理器進行管理,包括註冊感測器註銷感測器等操作)。
獲取用戶的經緯度信息需要使用位置管理器 LocationManager ,同時需要確認手機打開了位置服務。位置服務有一個位置的數據來源稱為 provider ,可以分為 NETWORK_PROVIDER 和 GPS_PROVIDER ,其中 NETWORK_PROVIDER 使用基站和 Wi-Fi 信號來決定用戶的位置,更新速度更快耗電量更少,但可能精確度較低,而 GPS_PROVIDER 使用 GPS 衛星進行定位,精度高但只能在室外使用,耗電量也更高。在使用過程中可以選擇使用其中一個 provider,也可以兩個provider 同時使用。在判斷使用哪個 Provider 的時候,首先使用 isProviderEnabled 函數判斷該 Provider 是否已經啟用,從而選取一個合適的 Provider:
在 Activity 在前臺運行(onResume)的時候註冊感測器,在離開前臺(onPause)的時候取消註冊。同時在註冊感測器的時候,需要指定感測器的監聽器,當感測器數據更新的時候,系統會回調監聽器里的 onSensorChange 函數,可以在這裡對感測器數據進行相應處理:
手機的朝向是通過地磁感測器和加速度感測器共同計算出來,Android 提供了計算這個數值的 API,首先通過 getRotationMatrix 得到一個旋轉矩陣,然後使用 getOrientation 得到手機的朝向:
在使用加速度感測器的時候我們可以實現檢測手機搖一搖的功能,這裡我實現了通過搖一搖,彈出是否退出應用的對話框,選擇是則退出應用:
對於位置信息的更新,可以註冊 LocationListener 監聽位置信息的更新並作出相應的處理,使用 getLastKnownLocation 可以立刻獲得一個位置坐標,如果之前有進行過定位操作,那麼這個位置就是之前獲取到的位置緩存,如果沒有獲得或位置,那麼返回一個空對象:
接下來實現地圖的相關功能。首先,寫好界面的 XML 佈局文件。這裡我們在佈局文件里添加百度地圖並需要設置一個 ToggleButton,並將 ToggleButton 背景設為@drawable/state,實現按鈕背景圖片的切換。
XML 文件如下:
背景 state.xml 文件如下:
在 Activity 中初始化百度地圖正常顯示地圖後,需要使用百度地圖裡MyLocationConfiguration 添加當前所在位置的箭頭,並根據用戶方向以及位置構造 MyLocationData ,相應設置箭頭的方向與位置:
LocationManager 返回的 Location 中的坐標系與百度地圖的坐標系並不一樣,需要進行坐標系的轉換,最後 LatLng 得到的經緯度為百度地圖坐標系下的經緯度:
在地圖中使顯示手機朝向的箭頭居中是使用 MapStatus 實現的(這裡設置ToggleButton 為 cheaked 狀態時顯示手機朝向的箭頭居中):
實現 BaiduMap 中的setOnMapTouchListener 函數來實現手動拖動地圖平移之後按鈕變化的功能:
在 ToggleButton 點擊事件、感測器監聽器等位置再次實現獲取當前位置信息的功能實現當按鈕處於狀態一時,如果 GPS 位置有更新,那麼更新用戶當前所在位置,並使得當前位置的箭頭圖標一直保持在屏幕中心;按鈕處於狀態二時,更新當前位置的箭頭的時候不移動地圖。
完成實驗~
可能遇到的問題及解決方法
在使用 locationManager.getLastKnownLocation(provider);時報錯,出現Call requires permission which may be rejected by user. Code shouldexplicitly check to see if permission is available.的錯誤,不知道怎樣解決。
解決方案:
在查詢了網上資料之後,瞭解到 Android 6.0 (SDK API level 23)新增了動態獲取許可權的特性。在獲取用戶信息時,需要檢查用戶是否授權,如果沒有授權則需要向用戶請求授權,對 Android 版本做相容處理,對於 Android 6 及以上版本需要向用戶請求授權,而低版本的則直接調用。
在加了以下語句後解決了此問題:
參考: http://majing.io/questions/226
http://blog.5ibc.net/p/62176.html
實驗截圖
實現搖一搖功能:
其他總結
Android 感測器框架讓你訪問許多類型的感測器。這些感測器的一些事基於硬體的,一些是基於軟體的。基於硬體的感測器是內嵌到手機或者平板中的物理元件,它們通過直接測量指定的環境屬性來得到它們的數據,例如加速度,磁場強度,或者角度變化。基於軟體的感測器不是物理設備,儘管它們模仿基於硬體的感測器。基於軟體的感測器從一個或更多基於硬體的感測器獲取它們的數據,並且有時候被稱為虛擬感測器或者合成感測器。線性加速度感測器和重力感測器是基於軟體感測器的例子。表 1 總結了 Android 平臺支持的感測器。很少 Android 設備有所有類型的感測器。例如,大部分手機和平板有一個加速計和磁場計,但是很少的設備擁有氣壓或者溫度感測器。並且,一個設備可以擁有一個類型不止一個的感測器。例如,設備能有兩個重力感測器,每個有不同的範圍。
大多數 Android 設備有內置的感測器,來測量運動,方向和各種環境條件。這些感測器能提供高精度和準確度的原始數據,如果你想監控設備三維運動或者位置,或者你想監控設備周圍的環境變化,是非常有用的。例如,游戲可能跟蹤設備重力感測器的數據,來推斷複雜的用戶首飾和動作,例如傾斜,震動,旋轉,或者振幅。同樣的,天氣應用可能使用設備的溫度感測器和濕度感測器的數據來計算和報告結露點,或者旅行應用可能使用磁場感測器和加速度感測器來報告一個指南針方位。
Android 平臺支持三大類的感測器:
(1)位移感測器
這些感測器測量沿三個軸線測量加速度和旋轉。這類包含加速度,重力感測器,陀螺儀,和矢量感測器。
(2)環境感測器
這些感測器測量各種環境參數,例如周圍的空氣溫度和壓力,光線,和濕度。這類包含氣壓,光線,和溫度感測器。
(3)位置感測器
這些感測器測量設備的物理位置。這類包含方向和磁力感測器。
我們可以訪問設備上可用的感測器,並通過使用 Android 感測器框架獲取原始感測器數據。感測器框架提供了一些類和介面,來幫助你執行各種感測器相關的任務。例如,你能使用感測器框架做如下事情:
(1)確定什麼感測器在設備上有效。
(2)確定當個感測器的功能,例如它的最大射程,廠商,電力需求,和解析度。
(3)獲取原始數據,並定義你獲取感測器數據的最小速率。
(4)註冊和註銷感測器事件監聽,來監聽感測器改變。
(額~這段話好繞口~ 話粗理不粗嘛~)
源碼下載
源碼下載點擊這裡~
註
1、本實驗實驗環境:
操作系統 Windows 10
實驗軟體 Android Studio 2.2.1
虛擬設備:Nexus_5X
API:23
2、貼代碼的時候由於插入代碼框的大小問題,代碼格式不太嚴整,望見諒~