Android傳感器簡介
最近單位項(xiàng)目遇到了搖一搖功能,正好把以前的筆記翻出來,整合到一起,發(fā)個(gè)文章,來吧,互相傷害吧.
<br />
本文代碼已上傳至Github:https://github.com/Xxxxxxyk/SensorDev
<br />
你真的了解我們?nèi)粘J褂玫氖謾C(jī)么? 平常你在玩微信搖一搖,手電筒,計(jì)步器的時(shí)候有沒有想過這些是怎么實(shí)現(xiàn)的呢?其實(shí)這些都?xì)w功于手機(jī)內(nèi)部的各種硬件傳感器.
認(rèn)識傳感器
在我們開始玩?zhèn)鞲衅髦?我們先來看下我們的手機(jī)中都有什么傳感器.
//獲取手機(jī)基本狀態(tài)及所有傳感器
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hardlist);
TextView tv_brand = (TextView) findViewById(R.id.tv_brand);
//手機(jī)號碼不一定能獲取到
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
tv_brand.setText("品牌: " + Build.BRAND + "\n" + "型號: " + Build.MODEL + "\n" + "Android版本: "
+ android.os.Build.VERSION.RELEASE + "\n" + "IMEI: " + tm.getDeviceId()
+ "\n" + "IMSI: " + tm.getSubscriberId() + "\n" + "手機(jī)號碼: " + tm.getLine1Number() + "\n"
+ "運(yùn)營商: " + tm.getSimOperatorName() + "\n");
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> allSensors = sm.getSensorList(Sensor.TYPE_ALL);// 獲得傳感器列表
RecyclerView rl_list = (RecyclerView) findViewById(R.id.rv_list);
rl_list.setLayoutManager(new LinearLayoutManager(this));
rl_list.setAdapter(new SensorAdapter(this,allSensors));
}
適配器:
public class SensorAdapter extends RecyclerView.Adapter<SensorAdapter.SensorViewHolder> {
private final Context context;
private final List<Sensor> sensors;
public SensorAdapter(Context context, List<Sensor> sensors) {
this.context = context;
this.sensors = sensors;
}
@Override
public SensorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
SensorViewHolder viewHolder = new SensorViewHolder(LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null));
return viewHolder;
}
@Override
public void onBindViewHolder(SensorViewHolder holder, int position) {
holder.mTv_text.setText("類型:" + getChineseName(sensors.get(position).getType()) + "\n" + "設(shè)備名稱:" + sensors.get(position).getName() + "\n設(shè)備版本" + sensors.get(position).getVersion() + "\n");
}
@Override
public int getItemCount() {
return sensors == null ? 0 : sensors.size();
}
class SensorViewHolder extends RecyclerView.ViewHolder {
private final TextView mTv_text;
public SensorViewHolder(View itemView) {
super(itemView);
mTv_text = (TextView) itemView.findViewById(android.R.id.text1);
}
}
public String getChineseName(int type) {
switch (type) {
case Sensor.TYPE_ACCELEROMETER:
return "加速度傳感器";
case Sensor.TYPE_GYROSCOPE:
return "陀螺儀傳感器";
case Sensor.TYPE_LIGHT:
return "環(huán)境光線傳感器";
case Sensor.TYPE_MAGNETIC_FIELD:
return "電磁場傳感器";
case Sensor.TYPE_ORIENTATION:
return "方向傳感器";
case Sensor.TYPE_PRESSURE:
return "壓力傳感器";
case Sensor.TYPE_PROXIMITY:
return "距離傳感器";
case Sensor.TYPE_TEMPERATURE:
return "溫度傳感器";
case Sensor.TYPE_GRAVITY:
return "重場傳感器";
case Sensor.TYPE_LINEAR_ACCELERATION:
return "線性加速度傳感器";
case Sensor.TYPE_ROTATION_VECTOR:
return "旋轉(zhuǎn)矢量傳感器";
case Sensor.TYPE_RELATIVE_HUMIDITY:
return "濕度傳感器";
case Sensor.TYPE_AMBIENT_TEMPERATURE:
return "溫度傳感器";
case Sensor.TYPE_GAME_ROTATION_VECTOR:
return "游戲旋轉(zhuǎn)矢量傳感器";
case Sensor.TYPE_STEP_COUNTER:
return "計(jì)步器";
case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
return "地磁旋轉(zhuǎn)矢量傳感器";
case Sensor.TYPE_SIGNIFICANT_MOTION:
return "特殊動作觸發(fā)傳感器";
default:
return "未知傳感器";
}
}
}
寫好之后我們來運(yùn)行試一下:
樓主用自己手機(jī)進(jìn)行測試的,華為榮耀8(吐槽一句,真難用),基本所有的傳感器都被識別了,沒有識別的兩個(gè)一個(gè)是霍爾傳感器(HALL),另一個(gè)是電話傳感器(PhoneCall).
傳感器開發(fā)
震動傳感器
官方文檔:https://developer.android.google.cn/reference/android/os/Vibrator.html
震動傳感器,顧名思義,手機(jī)振動全靠它,那么我們?nèi)绾慰刂莆覀兊氖謾C(jī)震動呢,上代碼:
public class VibratorUtils {
private final Vibrator mVibrator;
//震動傳感器
public VibratorUtils(Context context){
//獲取系統(tǒng)服務(wù)
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
//震動,time為震動時(shí)間
public void shock(long time){
mVibrator.vibrate(time);
}
}
很簡單,兩句代碼搞定,調(diào)用時(shí)只需要傳入時(shí)間即可,單位是s.(如果我們把時(shí)間調(diào)成好多好多秒,會不會有什么神奇的事情發(fā)生呢,我這么純潔肯定不知道)
閃光燈
官方文檔:https://developer.android.google.cn/reference/android/hardware/camera2/CameraManager.html
好了好了,不開車,接下來我們看看我們平常使用的手電筒是怎么實(shí)現(xiàn)的,需要注意的是,以下代碼只運(yùn)行在API21以上,并且你有閃光燈:
public class FlashLampUtils {
//閃光燈
private final CameraManager mSystemService;
public FlashLampUtils(Context context) {
//獲取系統(tǒng)服務(wù)
mSystemService = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
}
@TargetApi(Build.VERSION_CODES.M)
public void openLamp(){
if(!isLOLLIPOP()){
return;
}
try {
mSystemService.setTorchMode("0", true);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@TargetApi(Build.VERSION_CODES.M)
public void closeLamp(){
if(!isLOLLIPOP()){
return;
}
try {
mSystemService.setTorchMode("0", false);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 判斷Android系統(tǒng)版本
*
* @return boolean
*/
private boolean isLOLLIPOP() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return true;
} else {
return false;
}
}
}
只需要調(diào)用,閃光燈就可以亮起來了,除此之外,很多手機(jī)中都有手電筒的SOS功能,其實(shí)也非常簡單,大家可以自行嘗試.
指紋傳感器
官方文檔:https://developer.android.google.cn/reference/android/support/v4/hardware/fingerprint/package-summary.html
Google在API 23之后在官方API中加入了指紋API,方便用戶進(jìn)行指紋的一系列操作,那么我們怎么給我們自己的APP加入指紋功能呢,代碼如下:
public class FingerPrintUtils {
//指紋傳感器
public static final String TAG = "惜夢哥哥_";
private final FingerprintManagerCompat mManagerCompat;
public FingerPrintUtils(Context context) {
mManagerCompat = FingerprintManagerCompat.from(context);
}
public void checkFingerPrint(){
/**
* 檢查是否支持指紋識別
*/
if(mManagerCompat.hasEnrolledFingerprints()){
mManagerCompat.authenticate(null, 0, null, new FingerprintManagerCompat.AuthenticationCallback() {
/**
* 出現(xiàn)錯(cuò)誤回調(diào),多次嘗試失敗也會調(diào)用
*/
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
Log.e(TAG,errMsgId + "--------" + errString.toString());
}
/**
* 錯(cuò)誤信息提示
*/
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
Log.e(TAG,helpMsgId + "--------" + helpString.toString());
}
/**
* 當(dāng)驗(yàn)證的指紋成功時(shí)會回調(diào)此函數(shù)包警,然后取消監(jiān)聽
*/
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
Log.e(TAG,"驗(yàn)證成功");
}
/**
* 指紋驗(yàn)證失敗
*/
@Override
public void onAuthenticationFailed() {
Log.e(TAG,"驗(yàn)證失敗");;
}
}, null);
};
}
}
這里驗(yàn)證的指紋就是你在系統(tǒng)中設(shè)置的指紋,可以在回調(diào)中進(jìn)行不同操作.
光線傳感器
官方文檔:https://developer.android.google.cn/reference/android/hardware/Sensor.html#TYPE_LIGHT
光線傳感器是用來感應(yīng)手機(jī)周圍的亮度的,我們的手機(jī)上的自動調(diào)整亮度功能離不開這個(gè)傳感器,讓我們來看下你的周圍的亮度有多少吧
public class LightUtils {
private final Sensor mDefaultSensor;
private final SensorManager mSystemService;
//光線傳感器
public LightUtils(Context context) {
mSystemService = (SensorManager) context.getSystemService(SENSOR_SERVICE);
mDefaultSensor = mSystemService.getDefaultSensor(Sensor.TYPE_LIGHT);
}
public void getLightNum(SensorEventListener sensorEventListener) {
mSystemService.registerListener(sensorEventListener, mDefaultSensor, SensorManager.SENSOR_DELAY_UI);
}
}
調(diào)用時(shí)需要傳入SensorEventListener 對象,這個(gè)對象中有兩個(gè)方法,當(dāng)傳感器的值發(fā)生變化時(shí),會調(diào)用onSensorChanged方法,當(dāng)傳感器的精度發(fā)生變化時(shí),會調(diào)用onAccuracyChanged,這里我們只需要在onSensorChanged方法中處理我們的操作就可以
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
mBtn_light.setText("當(dāng)前亮度" + sensorEvent.values[0]);
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
加速傳感器
官方文檔:https://developer.android.google.cn/reference/android/hardware/Sensor.html#TYPE_ACCELEROMETER
加速傳感器,就是我們平常進(jìn)行搖(YUE)一(PAO)搖時(shí)采用的傳感器,手動臉紅.
//SensorManager代表了各類傳感器的集合
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
if (mSensorManager != null) {
//加速傳感器
mMSensorManagerDefaultSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (mMSensorManagerDefaultSensor != null) {
mSensorManager.registerListener(this, mMSensorManagerDefaultSensor, SensorManager.SENSOR_DELAY_UI);
}
}
加載完成傳感器之后在回調(diào)方法中進(jìn)行操作
private static final int UPTATE_INTERVAL_TIME = 50;
//靈敏度調(diào)節(jié)
private static final int SPEED_SHRESHOLD = 30;
private long lastUpdateTime;
private float lastX;
private float lastY;
private float lastZ;
........
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
long currentUpdateTime = System.currentTimeMillis();
long timeInterval = currentUpdateTime - lastUpdateTime;
if (timeInterval < UPTATE_INTERVAL_TIME) {
return;
}
lastUpdateTime = currentUpdateTime;
// 傳感器信息改變時(shí)執(zhí)行該方法
float[] values = sensorEvent.values;
float x = values[0]; // x軸方向的重力加速度,向右為正
float y = values[1]; // y軸方向的重力加速度诞挨,向前為正
float z = values[2]; // z軸方向的重力加速度莉撇,向上為正
float deltaX = x - lastX;
float deltaY = y - lastY;
float deltaZ = z - lastZ;
lastX = x;
lastY = y;
lastZ = z;
double speed = (Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / timeInterval) * 100;
if (speed >= SPEED_SHRESHOLD) {
mVibrator.vibrate(300);
Toast.makeText(this, "搖一搖震動", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
這里有個(gè)坑,大家要注意啦:
注冊監(jiān)聽器的時(shí)候需要在onStart方法中注冊,取消監(jiān)聽器需在onPause方法中取消,原因是因?yàn)锳ctivity的生命周期問題,避免按Home鍵之后感應(yīng)依舊存在,造成不必要的Bug.
@Override
protected void onStart() {
super.onStart();
shake();
}
@Override
protected void onPause() {
if (mSensorManager != null) {
mSensorManager.unregisterListener(this);
}
super.onPause();
}
結(jié)尾
好了,本次就介紹這個(gè)5個(gè)傳感器吧,希望大家可以嘗試一下,因?yàn)檫@個(gè)真的很好玩喲.最后再推薦一首歌,英文歌,但是真的很好聽: