传感器
概述
大多数安卓设备都内置了传感器,用来测量移动,方向和各种环境条件。
Android平台支持以下三类传感器:
- 这些传感器能够提供精度高且准确的原始数据。
- 如果要监视三维设备运动或定位,或者监视设备周围的环境变化,那么传感器会极其有用。
- 例如:游戏可以追踪设备重力感应器的读数来推断复杂的用户手势和动作,比如倾斜,摇晃,旋转或摆动。
- 同样地,天气应用程序可以使用设备温度传感器和湿度传感器来计算并报告dewpoint,旅行应用程序可以使用地磁传感器和加速计来报告罗盘方位。
1.运动传感器:这些传感器测量三个轴的加速力和旋转力。这一类别包括加速度计,重力感应器,陀螺仪和旋转矢量传感器。
2.环境传感器:这些传感器测量各种环境参数,例如环境空气温度和压力,照明和湿度。此类别包括了气压计,光度计和温度计。
3.位置传感器:这些传感器测量了设备的物理位置。此类别包括方向传感器和磁力计。
Google文档上把传感器类型分为传感器坐标轴、基础传感器和复合传感器(动作传感器、姿势传感器、未校准传感器和互动传感器)
更加具体的可以参考:https://source.android.google.cn/devices/sensors/sensor-types
获取本机支持的传感器
Android传感器框架是android.hardware包的一部分,包含下面的类和接口:
- SensorManager :你能使用这个类来创建一个传感器服务的实例。这个类提供了各种方法类访问和列举传感器,注册和注销传感器事件监听,并获取相应的信息。这个类也提供了几个传感器的常量,用户报告传感器的精确度,设置数据获取速率,和校准传感器。
- Sensor :你能使用这个类类创建一个指定传感器的实例。这个类提供了各种方法让你确定传感器的功能。
- SensorEvent :系统使用这个类来创建一个传感器对象,它提供了关于传感器事件的信息。一个传感器事件包含一下信息:原始传感器数据,这类传感器产生的事件,数据的准确性,和事件的时间戳。
- SensorEventListener :你能使用这个接口来创建两个回掉方法,当传感器的值改变或者当传感器的精度改变的时候,它接受通知(传感器事件)
SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
获取本机全部传感器列表
package com.example.sensor;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取系统传感器
SensorManager sm= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//通过传感器获取本机所有的传感器
List<Sensor> sensors=sm.getSensorList(Sensor.TYPE_ALL);
for (Sensor s:sensors){
Log.i("tag",s.toString());
}
}
}
获取指定传感器
可以通过下图的代码来获取指定的传感器, 需要选择合适的传感器类型
返回一个Sensor对象
//获取指定的某一个传感器,下面为加速度传感器
Sensor type_accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if(type_accelerometer!=null){
Log.i("type_accelerometer",type_accelerometer.toString());
}
传感器监听器
sm.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
//传感器数据变化,在该方中我们可以获取传感器变化的值
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//传感器精度变化
}
},type_accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
- SENSOR_ DELAY _GAME 如果利用传感器开发游戏, 建议使用该值。 一般大多数实时行较高的游戏使用该级别。 (20000微 秒)
- SENSOR_ DELAY NORMAL默认的获取传感器数据的速度。 标准延迟,对于- -般的益智类游戏或者EASY界别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧的现象。 (200000微秒)
- SENSOR DELAY_ _UI 若使用传感器更新U,建议使用该值。(60000微秒)
- SENSOR DELAY _FASTEST :最低延迟,-般不是特别灵敏的处理不推荐使用,该模式可能造成手机电量大量消耗,而且由于传递的为大量的原始数据,算法处理不好将会影响游戏逻辑和U的性能。(0微秒延迟)不推荐使用
传感器坐标系
通常,传感器框架使用一个标准的3维坐标系来表达数据值。对于大多数传感器, 当设备放置默认的方向(看下图) 的时候,坐标系被定义和设备的屏幕相关。当设备放置为它默认的方向,X轴是水平并指向右边,Y轴是竖直并指向上方,并且Z轴指向屏幕面的外侧。在这个系统,坐标系统有负的2值。这个坐标系被用于下面的传感器:
- 加速度传感器 (Acceleration sensor)
- 重力传感器(Gravity sensor)
- 陀螺仪传感器 (Gyroscope)
- 线性加速度传感器 (Linear acceleration sensor)
- 磁场传 感器(Geomagnetic field sensor)
许多传感器的传感器事件值在相对于设备静止的特定坐标系中表示。
sm.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
//传感器数据变化,在该方中我们可以获取传感器变化的值
float x=event.values[0];
float y=event.values[1];
float z=event.values[2];
textView_content.setText("x="+x+"y="+y+"z="+z);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//传感器精度变化
}
},type_accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
摇一摇
使用加速传感器实现摇一摇功能
Sensor type_accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sm.registerListener(new MySensorListener(this) ,type_accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
摇一摇打开音乐
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/content"
android:text="Hello World!" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="开始啦"
android:background="@android:color/holo_blue_light"
android:textSize="70sp"
android:visibility="gone"
android:gravity="center"
android:id="@+id/textView_start"
android:layout_gravity="center" />
</RelativeLayout>
package com.example.sensor;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TextView textView_content,textView_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView_content=findViewById(R.id.content);
textView_start=findViewById(R.id.textView_start);
//获取系统传感器
SensorManager sm= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//通过传感器获取本机所有的传感器
final List<Sensor> sensors=sm.getSensorList(Sensor.TYPE_ALL);
for (Sensor s:sensors){
Log.i("tag",s.toString());
}
//获取指定的某一个传感器,下面为加速度传感器
Sensor type_accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if(type_accelerometer!=null) {
Log.i("type_accelerometer", type_accelerometer.toString());
}
//注册传感器监听器
sm.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
//传感器数据变化,在该方中我们可以获取传感器变化的值
float x=event.values[0];
float y=event.values[1];
float z=event.values[2];
textView_content.setText("x="+x+"y="+y+"z="+z);
// Log.i("tag","x="+x+"y="+y+"z="+z);
if ((Math.abs(x)+Math.abs(y)+Math.abs(z))>=ringValue&&flag==false){
flag=true;
textView_start.setVisibility(View.VISIBLE);
MediaPlayer mp= MediaPlayer.create(MainActivity.this,R.raw.fyzx);
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
flag=false;
textView_start.setVisibility(View.GONE);
}
});
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//传感器精度变化
}
},type_accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
}
int ringValue=40;//三维XYZ三个值的总和达到这个值表示为摇晃
boolean flag = false;//表示是否已经在播放声音
}
温度传感器
Sensor type_ambient_temperature=sm.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
if (type_ambient_temperature != null) {
System.out.println(type_ambient_temperature.toString());
}
sm.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float temp=event.values[0];
System.out.println(temp);
temp= (float) (Math.round(temp*10.0)/10.0);
textView_temp.setText("温度:"+temp+"℃");
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
},type_ambient_temperature,SensorManager.SENSOR_DELAY_NORMAL);
}
自由的小方
- 定义一个小方块对象
- 定义一个视图,用于把小方块配置到屏幕上
- 通过重力传感器TYPE_GRAVIY控制小方块在屏幕上自由的行走(注意,自由是有一个度的,不能超出屏幕)
设置全屏
android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"
定义一个小方块对象
package com.example.sensor;
public class Rect {
float left=100,top=100,right=100,bottom=100;
private int width,height;
public Rect(int width,int height)
{
this.width=width;
this.height=height;
left=width/2-right/2;
top=height/2-bottom/2;
}
public float getBottom() {
return bottom;
}
public void setBottom(float bottom) {
this.bottom = bottom;
}
public float getLeft() {
return left;
}
public void setLeft(float left) {
this.left -= left;
if (this.left<=0)
{
this.left=0;
}
else if (this.left>=width-this.right)
{
this.left=width-this.right;
}
}
public float getRight() {
return right;
}
public void setRight(float right) {
this.right = right;
}
public float getTop() {
return top;
}
public void setTop(float top) {
this.top+= top;
if (this.top<=0)
{
this.top=0;
}
else if ( this.top>=height-this.bottom)
{
this.top=height-this.bottom;
}
}
}
定义一个视图
package com.example.sensor;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class RectView extends View {
Rect rect;
private int width,height;
Paint paint;
public RectView(Context context, int width, int height) {
super(context);
this.width=width;
this.height=height;
paint =new Paint();
paint.setColor(Color.GREEN);
rect=new Rect(width,height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(rect.getLeft(),rect.getTop(),rect.getRight()+rect.getLeft(),rect.getTop()+rect.getBottom(),paint);
}
}
通过重力传感器TYPE_GRAVIY控制小方块在屏幕上自由的行走
package com.example.sensor;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
public class Main2Activity extends Activity {
private RectView rectView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取屏幕宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
rectView = new RectView(this, dm.widthPixels, dm.heightPixels);
setContentView(rectView);
SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor type_gravity = sm.getDefaultSensor(Sensor.TYPE_GRAVITY);
sm.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
rectView.rect.setLeft(Math.round(x));
rectView.rect.setTop(Math.round(y));
rectView.invalidate();//屏幕重绘
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}, type_gravity, SensorManager.SENSOR_DELAY_GAME);
}
}