Android-感測器開發
阿新 • • 發佈:2020-12-21
感測器種類
感測器Sensor是一系列感測器的總稱,是Android裝置用來感知周圍環境和運動資訊的工具。因為工具的感應資訊依賴於相關硬體,所以雖然Android定義了多個感測器。但並非每部手機都支援這麼多感應器。
編號 | 型別 | 名稱 | 說明 |
---|---|---|---|
1 | TYPE_ACCELEROMETER | 加速度 | 常用於搖一搖功能 |
2 | TYPE_MAGNETIC_FIELD | 磁場 | |
3 | TYPE_ORIENTATION | 方向 | 已棄用,使用getOrientation方法 |
4 | TYPE_GYROSCOPE | 螺旋儀 | 用來感應手機的旋轉和傾斜 |
5 | TYPE_LIGHT | 光線 | 用來感應手機正面的光線強弱 |
6 | TYPE_PRESSURE | 壓力 | 用來感應氣壓 |
7 | TYPE_TEMPERATURE | 溫度 | 已棄用,使用型別13 |
8 | TYPE_PROXIMITY | 距離 | |
9 | TYPE_GRAVITY | 重力 | |
10 | TYPE_LINEAR_ACCELERATION | 線性加速度 | |
11 | TYPE_ROTATION_VECTOR | 旋轉向量 | |
12 | TYPE_RELATIVE_HUMIDITY | 相對溼度 | |
13 | TYPE_AMBIENT_TEMPERATURE | 環境溫度 | |
14 | TYPE_MAGNETIC_FIELD_UNCALIBRATED | 無標定磁場 | |
15 | TYPE_GAME_ROTATION_VECTOR | 無標定旋轉向量 | |
16 | TYPE_GYROSCOPE_UNCALIBRATED | 未校準陀螺儀 | |
17 | TYPE_SIGNIFICANT_MOTION | 特殊動作 | |
18 | TYPE_STEP_DETECTOR | 步行檢測 | 使用者每走一步觸發一次 |
19 | TYPE_STEP_COUNTER | 步行計數 | 記錄啟用後的步伐數 |
20 | TYPE_GEOMAGNETIC_ROTATION_VECTOR | 地磁旋轉向量 | |
21 | TYPE_HEART_RATE | 心跳速率 | 可穿戴裝置使用 |
22 | TYPE_TILT_DETECTOR | 傾斜檢測 | |
23 | TYPE_WAKE_GESTURE | 喚醒手勢 | |
24 | TYPE_GLANCE_GESTURE | 掠過手勢 | |
25 | TYPE_PICK_UP_GESTURE | 拾起手勢 |
檢視當前裝置支援的感測器種類,可通關呼叫SensorManager物件的getSensorList方法獲得,該方法返回了一個Sensor佇列。遍歷Sensor佇列中的每個元素,呼叫Sensor物件的getType方法可獲得該感測器的型別,呼叫Sensor物件的getName方法方法獲得該感測器的名稱。
例子
SensorActivity
public class SensorActivity extends AppCompatActivity {
private TextView tv_sensor;
private String[] mSensorType = {
"加速度", "磁場", "方向", "陀螺儀", "光線",
"壓力", "溫度", "距離", "重力", "線性加速度",
"旋轉向量", "溼度", "環境溫度", "無標定磁場", "無標定旋轉向量",
"未校準陀螺儀", "特殊動作", "步行檢測", "計步器", "地磁旋轉向量",
"心跳", "傾斜檢測", "喚醒手勢", "掠過手勢", "拾起手勢"};
private Map<Integer, String> mapSensor = new HashMap<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensor);
tv_sensor = findViewById(R.id.tv_sensor);
showSensorInfo(); // 顯示手機自帶的感測器資訊
}
private void showSensorInfo() {
// 從系統服務中獲取感測管理器物件
SensorManager mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// 獲取當前裝置支援的感測器列表
List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
String show_content = "當前支援的感測器包括:\n";
for (Sensor sensor : sensorList) {
if (sensor.getType() >= mSensorType.length) {
continue;
}
mapSensor.put(sensor.getType(), sensor.getName());
}
for (Map.Entry<Integer, String> item_map : mapSensor.entrySet()) {
int type = item_map.getKey();
String name = item_map.getValue();
String content = String.format("%d %s:%s\n", type, mSensorType[type - 1], name);
show_content += content;
}
tv_sensor.setText(show_content);
}
}
activity_sensor
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="5dp" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_sensor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="@color/black"
android:textSize="15sp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
加速度感測器
加速度感測器是最常見的感應器,大部分智慧手機都內建了加速度感測器。
以搖一搖為例演示加速度感測器開發步驟。
過程中用到了震動器可通過我之前的文章檢視。
AccelerationActivity
public class AccelerationActivity extends AppCompatActivity implements SensorEventListener {
private TextView tv_shake;
private SensorManager mSensorMgr; // 宣告一個感測管理器物件
private Vibrator mVibrator; // 宣告一個震動器物件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_acceleration);
tv_shake = findViewById(R.id.tv_shake);
// 從系統服務中獲取感測管理器物件
mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// 從系統服務中獲取震動器物件
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}
@Override
protected void onPause() {
super.onPause();
// 登出當前活動的感測監聽器
mSensorMgr.unregisterListener(this);
}
@Override
protected void onResume() {
super.onResume();
// 給加速度感測器註冊感測監聽器
mSensorMgr.registerListener(this,
mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 加速度變更事件
// values[0]:X軸,values[1]:Y軸,values[2]:Z軸
float[] values = event.values;
if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15
|| Math.abs(values[2]) > 15)) {
tv_shake.setText(DateUtil.getNowTime() + " 恭喜您搖一搖啦");
// 系統檢測到搖一搖事件後,震動手機提示使用者
mVibrator.vibrate(500);
}
}
}
// 當感測器精度改變時回撥該方法,一般無需處理
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}
activity_acceleration
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_shake"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="搖一搖看看有什麼"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
感光器
感光器也叫光線感測器,藉助與前置攝像頭的曝光,一旦遮住前置攝像頭,感測器監測到的光線強度立馬就會下降。在實際開發中,光線感測器往往用於感應手機正面的光線強弱,從而自動調節螢幕亮度。
LightActivity
public class LightActivity extends AppCompatActivity implements
CompoundButton.OnCheckedChangeListener, SensorEventListener {
private TextView tv_light;
private SensorManager mSensorMgr; // 宣告一個感測管理器物件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_light);
CheckBox ck_bright = findViewById(R.id.ck_bright);
// 檢查螢幕亮度是否為自動調節
if (SwitchUtil.getAutoBrightStatus(this)) {
ck_bright.setChecked(true);
}
// Android8.0之後普通應用不允許修改系統設定
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
ck_bright.setOnCheckedChangeListener(this);
} else {
ck_bright.setEnabled(false);
}
tv_light = findViewById(R.id.tv_light);
// 從系統服務中獲取感測管理器物件
mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.getId() == R.id.ck_bright) {
// 設定是否開啟螢幕亮度的自動調節
SwitchUtil.setAutoBrightStatus(this, isChecked);
}
}
@Override
protected void onPause() {
super.onPause();
// 登出當前活動的感測監聽器
mSensorMgr.unregisterListener(this);
}
@Override
protected void onResume() {
super.onResume();
// 給光線感測器註冊感測監聽器
mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LIGHT) { // 光線強度變更事件
float light_strength = event.values[0];
tv_light.setText(DateUtil.getNowTime() + " 當前光線強度為" + light_strength);
}
}
//當感測器精度改變時回撥該方法,一般無需處理
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}
activity_light
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<CheckBox
android:id="@+id/ck_bright"
android:layout_width="match_parent"
android:layout_height="40dp"
android:padding="5dp"
android:button="@null"
android:checked="false"
android:drawableLeft="@drawable/ck_status_selector"
android:text="亮度自動調節"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_gravity="left"
android:text="看看光線變化了沒有"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
SwitchUtil
public class SwitchUtil {
// 設定亮度自動調節的開關
public static void setAutoBrightStatus(Context ctx, boolean enabled) {
int screenMode = (enabled) ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
: Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
Settings.System.putInt(ctx.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE, screenMode);
}
// 獲取亮度自動調節的狀態
public static boolean getAutoBrightStatus(Context ctx) {
int screenMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
try {
screenMode = Settings.System.getInt(ctx.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE);
} catch (Exception e) {
e.printStackTrace();
}
return screenMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
}
}
ck_status_selector
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/switch_on" android:state_checked="true"/>
<item android:drawable="@drawable/switch_off" android:state_checked="false"/>
<item android:drawable="@drawable/switch_off"/>
</selector>
陀螺儀
陀螺儀顧名思義是測量平衡的儀器,它的測量結果未當前與上次位置之間的傾斜角度,這個角度描述的是三維空間的夾角,因而其數值由x,y,z,三個座標軸上的角度偏移組成。由於陀螺儀幾倍三維角度的測量功能,因此它又被稱為角速度感測器。
GyroscopeActivity
public class GyroscopeActivity extends AppCompatActivity implements SensorEventListener {
private static final float NS2S = 1.0f / 1000000000.0f; // 將納秒轉化為秒
private TextView tv_gyroscope;
private SensorManager mSensorMgr; // 宣告一個感測管理器物件
private float mTimestamp; // 記錄上次的時間戳
private float mAngle[] = new float[3]; // 記錄xyz三個方向上的旋轉角度
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gyroscope);
tv_gyroscope = findViewById(R.id.tv_gyroscope);
// 從系統服務中獲取感測管理器物件
mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}
@Override
protected void onPause() {
super.onPause();
// 登出當前活動的感測監聽器
mSensorMgr.unregisterListener(this);
}
@Override
protected void onResume() {
super.onResume();
// 獲取當前裝置支援的感測器列表
List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
boolean isSuitable = false;
for (Sensor sensor : sensorList) {
if (sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 找到陀螺儀
isSuitable = true;
break;
}
}
if (isSuitable) {
// 給陀螺儀感測器註冊感測監聽器
mSensorMgr.registerListener(this,
mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_FASTEST);
} else {
tv_gyroscope.setText("當前裝置不支援陀螺儀,請檢查是否存在陀螺儀感測器");
}
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 陀螺儀角度變更事件
if (mTimestamp != 0) {
final float dT = (event.timestamp - mTimestamp) * NS2S;
mAngle[0] += event.values[0] * dT;
mAngle[1] += event.values[1] * dT;
mAngle[2] += event.values[2] * dT;
// x軸的旋轉角度,手機平放桌上,然後繞側邊轉動
float angleX = (float) Math.toDegrees(mAngle[0]);
// y軸的旋轉角度,手機平放桌上,然後繞底邊轉動
float angleY = (float) Math.toDegrees(mAngle[1]);
// z軸的旋轉角度,手機平放桌上,然後水平旋轉
float angleZ = (float) Math.toDegrees(mAngle[2]);
String desc = String.format("陀螺儀檢測到當前x軸方向的轉動角度為%f,y軸方向的轉動角度為%f,z軸方向的轉動角度為%f",
angleX, angleY, angleZ);
tv_gyroscope.setText(desc);
}
mTimestamp = event.timestamp;
}
}
//當感測器精度改變時回撥該方法,一般無需處理
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}
activity_gyroscope
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="@+id/tv_gyroscope"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="請上下左右轉動手機檢視陀螺儀"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>