一.Android传感器的基础概念
随着手机的发展,现在各大手机支持的传感器类型也越来越多,在开发中利用传感器进行某些操作令人们有一种耳目一新的感觉,例如微信中的摇一摇,以及手机音乐播放器中的摇一摇切歌。今天来简单介绍下Android中传感器的使用以及一些常用的传感器。
(一)传感器种类
1.动作传感器
Android平台支持一些用于监视设备动作的传感器(这样的传感器共有5个)。其中两个 (加速传感器( TYPE_ACCELEROMETER)和陀螺仪(TYPE_GYROSCOPE)传感器)是纯的硬件传感器。 另外三个(重力传感器、线性加速传感器和旋转向量传感器)可能是硬件传感器,也可能 是软件传感器。例如,在一些Android设备中,这些基于软件的传感器会从加速和磁力传感器中获取数 据,但在另一些Android设备中也可能从陀螺仪传感器中获取数据。也就是说,同一种基于软件的传感器在不同的Android设备中回传的数据可能来自不同的硬件传感器。所以基于软件的同一种传感器在不同的设备中可能精确度、使用范围有所不同。大多数高端 Android设备都会有加速传感器,还有一些拥有陀螺仪传感器。
2.位置传感器
Android平台提供了两个传感器用于确定设备的位置,这两个传感器是磁场传感器和方向传感器。Android平台还提供了测量设备正面到某一个邻近物体距离的传感器(邻近传感 器)。磁场传感器和邻近传感器是基于硬件的传感器。大多数Android手机和平板电脑都 有磁场传感器。而邻近传感器通常在手机中很常见。因为可以用该传感器测试接听电话时 手机屏幕离脸有多远。可以可以在贴近耳朵接听电话时完成某些工作。方向传感器是基于 软件的,该传感器的回传数据来自加速度传感器和磁场传感器。
3.环境传感器
Android平台提供了4个传感器,用于检测不同的外部环境。我们可以使用这些传感器检测 周围。例如,可以检测周围空气的湿度、光线、空气的压强和温度。这4个传感器都是基于 硬件的传感器。除了光线传感器外,其他3个传感器在普通的Android设备中很少见。所以 如果使用环境传感器,最好运行时对当前Android设备所支持的传感器是否检测。
(二)Android传感器一览表
传感器类型名称 传感器类别 系统定义的传感器常量 传感器常量对应的数值
1. 加速度 TYPE_ACCELEROMETER SENSOR_TYPE_ACCELEROMETER 1
2. 磁力域 TYPE_MAGNETIC_FIELD SENSOR_TYPE_MAGNETIC_FIELD 2
3. 方向 TYPE_ORIENTATION SENSOR_TYPE_ORIENTATION 3
4. 陀螺 TYPE_GYROSCOPE SENSOR_TYPE_GYROSCOPE 4
5. 光线(亮度)TYPE_LIGHT SENSOR_TYPE_LIGHT 5
6. 压力 TYPE_PRESSURE SENSOR_TYPE_PRESSURE 6
7. 温度 TYPE_TEMPERATURE SENSOR_TYPE_TEMPERATURE 7
8. 临近性 TYPE_PROXIMITY SENSOR_TYPE_PROXIMITY 8
(三)SensorManager管理器
1.SensorManager获取所有传感器
Android所有的传感器都归传感器管理器 SensorManager 管理,获取传感器管理器的方法很简单:
SensorManager sensorManager = (SensorManager)getSystemService(Context.S ENSOR_SERVICE);
(四)从传感器管理器中获取其中某个或者某些传感器的方法有如下三种:
第一种:获取某种传感器的默认传感器
Sensor defaultGyroscope = sensorManager.getDefaultSensor(Sensor. TYPE_GYROSCOPE);
第二种:获取某种传感器的列表
List<Sensor> pressureSensors = sensorManager.getSensorList(Sensor.TYPE_PRESSURE);
第三种:获取所有传感器的列表
List<Sensor> allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
(五)对于某一个传感器,它的一些具体信息的获取方法可以见下表:
1. getMaximumRange() 最大取值范围
2. getName() 设备名称
3. getPower() 功率
4. getResolution() 精度
5. getType() 传感器类型
6. getVentor() 设备供应商
7. getVersion() 设备版本号
(六)注册SensorListener
注册传感器监听状态的改变,能在状态改变的回调方法中,操作相应的行为。
注册SensorListener的方法,三个参数
sensorManager.regesterListener(SensorEventListener listener, Sensor sensor, int rate);
第一个参数为传感器监听
第二个参数为当前注册的传感器
第三个参数是延迟时间的精密度,
精密度可选择的值
1.SensorManager.SENSOR_DELAY_FASTEST 0ms
2.SensorManager.SENSOR_DELAY_GAME 20ms
3.SensorManager.SENSOR_DELAY_UI 60ms
4.SensorManager.SENSOR_DELAY_NORMAL 200ms
(七)取消注册SensorManager
一般在onDestroy方法里面取消。
sensorManager. unregisterListener(SensorEventListener listener);
(八)SensorEventListener监听
要监视原始的传感器数据,你需要实现两个通过SensorEventListener接口暴露的回调方法:onAccuracyChanged()和onSensorChanged()。
Android系统在任何发生下列事情的时 候都会调用这两个方法:
1.onAccuracyChanged传感器精度的改变:
这种情况中,系统会调用onAccuracyChanged()方法,它提供了你要引用的发生精度变化的 Sensor对象。精度使用以下四个状态常量之一来代表的:
(1) SENSOR_STATUS_ACCURACY_LOW
(2) SENSOR_STATUS_ACCURACY_MEDIUM
(3)SENSOR_STATUS_ACCURACY_HIGH
(4) SENSOR_STATUS_UNRELIABLE
2.onSensorChanged传感器报告新的值:
这个也是我们一般情况下去重写的回调方法。
这种情况中,系统会调用onSensorChanged()方法,它提供了一个SensorEvent对象。 SensorEvent对象包含了有关新的传感器数据的信息,包括:数据的精度、产生数据的传感器、产生数据时的时间戳、以及传感器记录的新的数据。
注意:传感器是非常耗电的,在不用时一定要释放。
二.几种重要的传感器详细介绍
(一)动作传感器的作用
动作传感器对于监测设备的移动非常有用,例如,倾斜、震动、旋转和摆动都属于动作传感器的监 测范围。设备的移动通常是对用户输入的直接反应。例如,用户正在游戏中飙车,或控制游戏中的一个小球)。除此之外,设备所处的物理环境也会反应在设备的动作上,例如,用户正常驾驶汽车,而这是 Android设备正安静地躺在旁边的座椅上,尽管设备没有移动,但会随着车的行驶而不断震动,而且 设备也会随着汽车的移动而移动。 对于第一种情况,可以对设备本身的相对位置进行监测。而对于第二种情况,需要考虑到设备以外的参 照系。动作传感器本身一般并不会用于监测设备的位置,关于设备的位置需要用其他类型的传感器进行 监测,例如,磁场传感器。
(二)动作传感器的回传数据
所有的动作传感器都会返回三个浮点数的值(通过长度为3的数组返回),但对于不同的传感器,这三个只的意义不同。例如,对于加速传感器,会返回三个坐标轴的数据[。对于陀螺仪传感器,会返回三个坐标轴的旋转角速度。
应用:动作传感器_摇一摇
(三)方向传感器
方向传感器有三个方向的属性值。
1.SensorEvent.values[0]: 绕着Z轴旋转的角度。
如果Y轴(正常拿手机的方向)正对着北方,该值是0,如果Y轴指向南 方,改值是180,Y轴指向东方,该值是90,如果Y轴指向西方,该值是270。
2.SensorEvent.values[1]: 绕着X轴旋转的度数。
当从Z轴正方向朝向Y轴正方向,改值为正值。反之,为负值。该值在 180至-180之间变动。
3.ensorEvent.values[2]:绕着Y轴旋转的度数。
从Z轴正方向朝向X轴正方向,改值为正值。反之,为负值。该值在180至-180之间变动。 应用:方向传感器_指南针
(四)磁场传感器
这个传感器一般开发不会用到!
SensorEvent.values[0]: 沿着X轴的磁力(μT,millitesla) SensorEvent.values[1]: 沿着Y轴的磁力(μT,millitesla) SensorEvent.values[2]: 沿着Z轴的磁力(μT,millitesla)
(五)邻近传感器
这里只返回一个参数
SensorEvent.values[0]:
手机正面距离邻近物理的距离(CM)
应用:手机接电话时屏幕熄屏
(六)光线传感器的一些值的标准
- 最强的光线强度(估计只有沙漠地带才能达到这个值)
public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
2.万里无云时阳光直射的强度
public static final float LIGHT_SUNLIGHT = 110000.0f; - 有阳光,但被云彩抵消了部分光线时的强度
public static final float LIGHT_SHADE = 20000.0f; 4.多云时的光线强度
public static final float LIGHT_OVERCAST = 10000.0f;
5.太阳刚刚升起时(日出)的光线强度
public static final float LIGHT_SUNRISE = 400.0f;
6.在阴雨天,没有太阳时的光线强度
public static final float LIGHT_CLOUDY = 100.0f;
7.夜晚有月亮时的光线强度
public static final float LIGHT_FULLMOON = 0.25f;
8.夜晚没有月亮时的光线强度(当然,也不能有路灯,就是漆黑一片)
public static final float LIGHT_NO_MOON = 0.001f;
一般的传感器的使用时不用权限的,比如摇一摇,控制屏幕中图像的上下左右滚动等等。
三.传感器使用的一个简单示例
本示例只要是显示手机中存在的传感器的类型在List View中罗列出来。
(一)布局文件activity_main.xml的设计
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:padding="20dp"
android:id="@+id/main_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text" />
</HorizontalScrollView>
<ListView
android:id="@+id/main_lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
布局中使用一个ScrollView来显示某一个具体的传感器的所有的数据,使用一个ListVIew显示所有的传感器的类型。
(二)java代码的设计
package com.lwz.sensor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
/**
* 传感器的使用
*/
public class MainActivity extends AppCompatActivity {
//定义传感器的管理器
SensorManager sensorManager;
//定义布局内的控件
ListView listView;
TextView tv;
//获取所有的管理器
List<Sensor> sensors;
//获取某一种传感器
Sensor sensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE); //实例化传感器的管理器
listView = (ListView) findViewById(R.id.main_lv);//实例化布局
tv = (TextView) findViewById(R.id.main_tv);
initTv();
//获取所有的管理器
sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
listView.setAdapter(adapter);
}
/**
* 给TextView设置一个文本,某一个类型的传感器的具体数据
* 这里显示的是加速传感器的数据
*/
private void initTv() {
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (sensor != null) {
String name = sensor.getName();//名称
float range = sensor.getMaximumRange();//最大取值范围
float power = sensor.getPower();// 功率
float resol = sensor.getResolution();// 精度
int type = sensor.getType(); //传感器类型
String vendor = sensor.getVendor(); //设备供应商
int version = sensor.getVersion(); //设备版本号
tv.setText("名称" + name + ",最大取值范围" + range + ",功率" + power +
",精度" + resol + ",传感器类型" + type + ",供应商" + vendor + ",版本号" + version);
} else {
tv.setText("没有该传感器的数据显示");
}
}
private BaseAdapter adapter = new BaseAdapter() {
@Override
public int getCount() {
return sensors.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(getBaseContext(), android.R.layout.simple_list_item_1, null);
}
TextView tv = (TextView) convertView;
Sensor sensor = sensors.get(position);
tv.setText(position + ":" + sensor.getName() + " ");
switch (sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
tv.append(" 加速度传感器");
break;
case Sensor.TYPE_LIGHT:
tv.append(" 光线");
break;
case Sensor.TYPE_GRAVITY:
tv.append(" 重力");
break;
default:
tv.append(" 其他");
break;
}
return convertView;
}
};
/***
* 在onStart中注册传感器的监听事件
*/
@Override
protected void onStart() {
super.onStart();
//精准度
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
}
/**
* 传感器的监听对象
*/
SensorEventListener listener = new SensorEventListener() {
//传感器改变时,一般是通过这个方法里面的参数确定传感器状态的改变
@Override
public void onSensorChanged(SensorEvent event) {
// Log.e("TAG", "-------传感状态发生变化-------");
//获取传感器的数据
float[] values = event.values;
float max = sensor.getMaximumRange();//获取最大值范围
if (values.length >= 3) {
float x = values[0];
float y = values[1];
float z = values[2];
if (x > max / 5) {
Log.e("TAG", "--------------" + max + " " + x + " " + y + " " + z);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//当精准度改变时
}
};
/***
* 在onDestroy中注销传感器的监听事件
*/
@Override
protected void onDestroy() {
super.onDestroy();
sensorManager.unregisterListener(listener);
}
}
(三)程序运行后的界面:
注意这里每一个手机显示的传感器的个数一般不相同,模拟器显示很少种类,一般手机都能显示4、5个,好一点的手机会显示9个或更多。
手机模拟器的显示情况:
真机显示情况:
另外在AndroidStudio中也会显示很多的Log信息,这里先不展示。
四.设计一个跟随屏幕翻动而滚动的小球的示例
这里利用的是方向传感器,但是只取其中的两个方向就可以实现了。
(一)创建一个自定义View来显示小球和简单背景
package com.lwz.sensor;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;
/**
* 自定义的小球
*/
public class MyView extends View {
public MyView(Context context) {
super(context);
initView();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
//创建画笔
Paint paint = new Paint();
//设置一个圆心的点
Point point = new Point();
int width;
int height;
int currentX;
int currentY;
//初始化数据
void initView() {
//对画笔的基本设置
//设置抗锯齿
paint.setAntiAlias(true);
//设置防抖动
paint.setDither(true);
//设置颜色
paint.setColor(Color.RED);
//设置透明的
paint.setAlpha(128);
//设置线条粗细
paint.setStrokeWidth(10);
width = getResources().getDisplayMetrics().widthPixels;
height = getResources().getDisplayMetrics().heightPixels;
currentX = width / 2;
currentY = height / 2;
point.set(width / 2, height / 2);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制多条直线
canvas.drawLines(new float[]{0, height / 2, width
, height / 2, width / 2, 0, width / 2, height,}, paint);
paint.setStyle(Paint.Style.FILL);//
//绘制一个实心圆(默认情况)
canvas.drawCircle(currentX, currentY, 50, paint);
//画一个空心圆也设置画笔
paint.setStyle(Paint.Style.STROKE);//
canvas.drawCircle(width / 2, height / 2, width / 2, paint);
}
//当屏幕方向发生改变时,调用这个方法对小球进行重绘
public void initdata(int x, int y) {
currentX = currentX-x;
currentY = currentY-y;
invalidate();//重绘
}
}
(二)布局文件的设计
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.lwz.sensor.MyView
android:layout_centerInParent="true"
android:id="@+id/second_myView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
(三)主方法的java代码
package com.lwz.sensor;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
/**
* 跟随的小球的设置
*/
public class SecondActivity extends Activity {
//定义传感器的管理器
SensorManager sensorManager;
//定义布局内的控件
MyView myView;
//获取某一种传感器
Sensor sensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bor);
myView= (MyView) findViewById(R.id.second_myView);
sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE); //实例化传感器的管理器
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
/***
* 在onStart中注册传感器的监听事件
*/
@Override
protected void onStart() {
super.onStart();
//注册监听传感状态
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
}
/**
* 传感器的监听对象
*/
SensorEventListener listener = new SensorEventListener() {
//传感器改变时,一般是通过这个方法里面的参数确定传感器状态的改变
@Override
public void onSensorChanged(SensorEvent event) {
// Log.e("TAG", "-------传感状态发生变化-------");
//获取传感器的数据
float[] values = event.values;
float max = sensor.getMaximumRange();//获取最大值范围
if (values.length >= 3) {
float x = values[0];
float y = values[1];
float z = values[2];
if (Math.abs(x) > max / 8) {
myView.initdata((int)x,(int)y);
}
if (Math.abs(y) > max /8) {
myView.initdata((int)x,-(int)y);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//当精准度改变时
}
};
/***
* 在onDestroy中注销传感器的监听事件
*/
@Override
protected void onDestroy() {
super.onDestroy();
sensorManager.unregisterListener(listener);
}
}
传感器的测试要在真机中运行。
程序运后显示的界面:
当手机往右边和下边倾斜后显示的效果:
但手机向某一个方向倾斜,小球就会想某个方向去滑动,这里小球没有设置边界,所以小球会滑出屏幕外面,想要设置其实也是很简单的,在MyView里面设置就可以了。
关于Android传感器的使用并不是很多,一般的学会使用加速度传感器和方向传感器就可以了。而且使用它们都是不用添加权限的。