網站首頁 編程語言 正文
1 傳感器簡介
傳感器 Sensor 是一種檢測裝置,能感受到被測量的信息,并能將感受到的信息,按一定規律變換成為電信號或其他所需形式的信息輸出,以滿足信息的傳輸、處理、存儲、顯示、記錄和控制等要求。 Android 提供了對設備傳感器的支持,只要 Android 設備的硬件提供了這些傳感器,Android 應用可以通過傳感器來獲取設備的外界條件,包括手機的運行狀態、當前擺放的方向等。Android 系統還提供了驅動程序去管理這些傳感器硬件,可以通過監聽器的方式監聽傳感器硬件感知到的外部環境的變化。
Android 平臺支持三大類傳感器:
類別 | 傳感器 | 說明 |
運動傳感器 | TYPE_ACCELEROMETER | 加速度傳感器,基于硬件 |
TYPE_GRAVITY | 重力傳感器,基于硬件或軟件 | |
TYPE_GYROSCOPE | 陀螺儀傳感器,基于硬件 | |
TYPE_ROTATION_VECTOR | 旋轉矢量傳感器,基于硬件或軟件 | |
TYPE_LINEAR_ACCELERATION | 線性加速度傳感器,基于硬件或軟件 | |
位置傳感器 | TYPE_MAGNETIC_FIELD | 磁力傳感器,基于硬件 |
TYPE_ORIENTATION | 方向傳感器,基于軟件 | |
TYPE_PROXIMITY | 距離傳感器,基于硬件 | |
環境傳感器 | TYPE_LIGHT | 光線感應傳感器,基于硬件 |
TYPE_PRESSURE | 壓力傳感器,基于硬件 | |
TYPE_TEMPERATURE | 溫度傳感器,基于硬件 |
有些傳感器基于硬件,有些基于軟件?;谟布膫鞲衅魇莾戎迷谑謾C或平板設備中的物理組件。這類傳感器通過直接測量特定的環境屬性(如加速度、地磁場強度或角度變化)來采集數據。基于軟件的傳感器不是物理設備,它們只是模仿基于硬件的傳感器。基于軟件的傳感器從一個或多個基于硬件的傳感器獲取數據,有時被稱為虛擬傳感器或合成傳感器。比如線性加速度傳感器和重力傳感器就是基于軟件的傳感器。
傳感器棄用說明:
- Android 2.2(API 級別 8)已棄用方向傳感器,Android 4.4W(API 級別 20)已棄用此傳感器類型 TYPE_ORIENTATION。替代方法見后面示例代碼。
- 溫度傳感器已在 Android 4.0(API 級別 14)中棄用,不同設備具有不同的實現。
2 傳感器的使用
2.1 獲取傳感器服務
Android 中內置了很多系統級的服務,用于給開發人員使用,而傳感器也是通過傳感器服務 SensorManager 來管理的。而在 Android 組件中獲取系統服務,使用方法 Context.getSystemService(String) 即可,它的參數均以 static final 的方式定義在 Context 中,而獲取 SensorManager 需要傳入 Context.SENSOR_SERVICE。
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
2.2 獲取待監聽的傳感器
傳感器服務管理設備上所有的傳感器,所以需要獲取待監聽的傳感器。 可以通過在 getSensorList() 方法中傳入 TYPE_ALL 來獲取設備上的所有傳感器:
List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
也可以通過指定的 type 參數獲取到相對應的傳感器,如果設備上有多個特定類型的傳感器,則必須將其中一個指定為默認傳感器。如果沒有指定默認傳感器,則該方法調用會返回 null,這表示設備沒有該類型的傳感器。
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
注意使用前先判斷傳感器是否存在。
運行時檢測。
if (sensor != null) {
//傳感器存在
} else {
//傳感器不存在
}
使用清單文件來限定目標設備必須帶有指定傳感器配置。
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
對于某一個傳感器,它的一些具體信息的獲取方法如下:
- getMaximumRange() 最大取值范圍
- getName() 設備名稱
- getPower() 功率
- getResolution() 精度
- getType() 傳感器類型
- getVentor() 設備供應商
- getVersion() 設備版本號
2.3 注冊傳感器的監聽器
獲得 SensorManager 和 Sensor 對象之后,就可以為其 Sensor 注冊監聽器了。為傳感器注冊監聽器,使用 SensorManager.registerListener() 方法即可,它存在多個重載方法,但是有些方法已經過時了,下面提供一個常用的方法:
boolean registerListener(SensorEventListener listener,Sensor sensor,int rateUs)
上面方法參數的意義:listener:傳感器的監聽器、sensor:待監聽的傳感器、rateUs:傳感器的采樣率。 從 registerListener() 方法可以看出,它需要傳遞一個 SensorEventListener 對象,它就是傳感器的監聽器,其中包含兩個方法,需要開發人員去實現它:
- void onSensorChanged(SensorEvent event):當傳感器感應的值發生變化時回調。
- void onAccuracyChanged(Sensor sensor,int accuracy):當傳感器精度發生變化時回調。 對于上面兩個方法,傳感器的精度一般是不會發生改變的,所以我們一般主要的代碼量在 onSensorChanged()中。
在 onSensorChanged(SensorEvent event) 方法中有一個參數 event,通過 event 可以獲取傳感器的類型以及傳感器的數據。
- 獲取傳感器的類型:event.sensor.getType()
- 獲取傳感器的數據:event.values[i],i為0,1,2...,不同傳感器,event.values[i] 對應的數據不同。以加速度傳感器為例,values[0] 表示x軸上的加速度,values[1] 表示y軸上的加速度,values[2] 表示z軸上的加速度。
registerListener() 方法還有一個 rateUs 的參數,它表示監聽傳感器改變的采樣率,就是從傳感器獲取值的頻率。它被定義以 static final 的形式定義在 SensorManager 中,方便我們直接使用,它定義了如下幾個參數:
參數 | 延時 | 說明 |
---|---|---|
SensorManager.SENSOR_DELAY_FASTEST | 0ms | 一般不是特別敏感的處理不推薦使用,該種模式可能造成手機電力大量消耗,由于傳遞的為原始數據,算法不處理好將會影響游戲邏輯和 UI 的性能。 |
SensorManager.SENSOR_DELAY_GAME | 20ms | 一般絕大多數的實時性較高的游戲都使用該級別。 |
SensorManager.SENSOR_DELAY_UI | 60ms | 適合普通用戶界面 UI 變化的頻率,相對節省電能和邏輯處理,一般游戲開發中不使用。 |
SensorManager.SENSOR_DELAY_NORMAL | 200ms | 對于一般的益智類或 EASY 級別的游戲可以使用,但過低的采樣率可能對一些賽車類游戲有跳幀現象。 |
Android 為我們提供了這幾個采樣率的參數,方便我們使用。但對于選擇那種采樣率而言,并不是越快越好,要參照實際開發的應用的情況來說,采樣率越大,將越耗費資源,包括電量、CPU 等,所以要根據實際情況選擇,畢竟再強大的應用,如果造成設備續航能力的降低,也是會被用戶所不喜的。
2.4 注銷傳感器的監聽器
當使用完傳感器之后,需要為其注銷監聽器,因為傳感器的監聽器并不會因為應用的結束而自行釋放資源,需要開發人員在適當的時候主動注銷。注銷傳感器監聽器使用 SensorManager.unregisterListener() 方法即可,和監聽器的注冊方法一樣,它也具有多個重載的方法,但是有一些已經被棄用了,下面介紹一個常用的:
void unregisterListener(SensorEventListener listener)
3 示例代碼
Java 代碼如下:
public class MainActivity extends AppCompatActivity {
private final String TAG = "sensor-sample";
private TextView mAccelerometerSensorTextView;
private TextView mMagneticSensorTextView;
private TextView mGyroscopeSensorTextView;
private TextView mOrientationSensorTextView;
private SensorManager mSensorManager;
private MySensorEventListener mMySensorEventListener;
private float[] mAccelerometerReading = new float[3];
private float[] mMagneticFieldReading = new float[3];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAccelerometerSensorTextView = findViewById(R.id.accelerometer_sensor);
mMagneticSensorTextView = findViewById(R.id.magnetic_sensor);
mGyroscopeSensorTextView = findViewById(R.id.gyroscope_sensor);
mOrientationSensorTextView = findViewById(R.id.orientation_sensor);
this.mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
this.mMySensorEventListener = new MySensorEventListener();
}
@Override
protected void onResume() {
super.onResume();
if (mSensorManager == null) {
return;
}
Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometerSensor != null) {
//register accelerometer sensor listener
mSensorManager.registerListener(mMySensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Accelerometer sensors are not supported on current devices.");
}
Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (magneticSensor != null) {
//register magnetic sensor listener
mSensorManager.registerListener(mMySensorEventListener, magneticSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Magnetic sensors are not supported on current devices.");
}
Sensor gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (gyroscopeSensor != null) {
//register gyroscope sensor listener
mSensorManager.registerListener(mMySensorEventListener, gyroscopeSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Gyroscope sensors are not supported on current devices.");
}
}
@Override
protected void onPause() {
super.onPause();
if (mSensorManager == null) {
return;
}
//unregister all listener
mSensorManager.unregisterListener(mMySensorEventListener);
}
/*
This orientation sensor was deprecated in Android 2.2 (API level 8), and this sensor type was deprecated in Android 4.4W (API level 20).
The sensor framework provides alternate methods for acquiring device orientation.
*/
private void calculateOrientation() {
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometerReading, mMagneticFieldReading);
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);
Log.d(TAG, "orientation data[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
mOrientationSensorTextView.setText("[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
}
private class MySensorEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mAccelerometerReading = event.values;
Log.d(TAG, "accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mAccelerometerSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mMagneticFieldReading = event.values;
Log.d(TAG, "magnetic data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mMagneticSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
Log.d(TAG, "gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mGyroscopeSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
}
calculateOrientation();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.d(TAG, "onAccuracyChanged:" + sensor.getType() + "->" + accuracy);
}
}
}
運行效果如下:
原文鏈接:https://juejin.cn/post/7120052450576302117
相關推薦
- 2022-08-23 C++深入講解函數重載_C 語言
- 2022-09-06 C語言常見排序算法歸并排序_C 語言
- 2022-06-16 Golang項目搭配nginx部署反向代理負載均衡講解_Golang
- 2022-10-17 Python?實操顯示數據圖表并固定時間長度_python
- 2022-04-04 切換路由時如何關閉上一個頁面的所有請求-axios cancelToken
- 2022-11-07 C語言字符串函數模擬實現流程介紹_C 語言
- 2022-11-25 使用PyTorch常見4個錯誤解決示例詳解_python
- 2022-03-16 Android線程池源碼閱讀記錄介紹_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支