现在每部Android手机里边都会内置有许多传感器,如光照传感器、加速度传感器、地磁传感器、压力传感器、温度传感器等,它们能够监测到各种发生在手机撒花姑娘的物理事件。当然Android系统只是负责将这些传感器所输出的信息传递给我们,然后我们可以利用这些信息去开发一些好玩的应用。
每种传感器的用法步骤几乎都一样,只是不同传感器的数据参数会有略微不同,这里以光照传感器为例,介绍一些Android传感器的使用步骤:
①获取SensorManager的实例
SensorManager sensorManager= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
②SensorManager是系统所有传感器的管理器,有了它的实例后就可以调用getDefaultSensor()方法来得到任意的传感器类型。
Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_LIGHT);
③然后我们需要对传感器输出的信号进行监听,这就要借助SensorEventListener来实现,SensorEventListener是一个接口,其中定义了onSensorChanged()和onAccuracyChanged()两个方法。当传感器的精度发生变化时就会调用onAccuracyChanged()方法,当监测到的数值发生变化时就会调用onSensorChanged()方法,方法中传入一个SensorEvent参数,这个参数里又包含一个values数组,所有传感器输出的信息都存放在这里。
SensorEventListener listener=new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
④下面我们需要调用SensorManager的registerListener()方法来注册SensorEventListener才能使其生效,registerListener()方法接收3个参数,第一个参数就是SensorEventListener的实例,第一个参数是Sensor的实例,第三个参数是用于表示传感器输出信息的更新速率,共有SENSOR_DELAY_UI、SENSOR_DELAY_NORMAL、SENSOR_DELAY_GAME和SENSOR_DELAY_FASTEST这四种值可选,其更新速率依次递增!
sensorManager.registerListener(listener,sensor,SensorManager.SENSOR_DELAY_GAME);
⑤当程序退出或传感器使用完毕时,一定要调用方法unregisterListener()将其使用的资源释放掉:
@Override
protected void onDestroy() {
super.onDestroy();
if (sensorManager!=null){
sensorManager.unregisterListener(listener);
}
}
注意:
1. 加速度传感器输出的信息存放的values数组中有3个值,分别代表手机在X轴,Y轴和Z轴方向上的加速度信息。由于地心引力的存在,手机都会有一个重力加速度9.8m/s²。当手机平放时,这个加速度作用在Z轴上,竖立时,这个加速度作用在Y轴上,当手机横立时,这个加速度作用在X轴。
2. 方向传感器,Sensor.TYPE_ORIENTATION,它输出的值在values数组中,values[0]记录手机围绕Z轴的旋转角度,values[1]记录手机围绕X轴的旋转角度,values[2]记录手机围绕Y轴的旋转角度。但是Android早已废弃了Sensor.TYPE_ORIENTATION这种传感器类型,而是通过加速度传感器和地磁传感器共同计算得出。
上边提到方向传感器已经由加速度传感器和地磁传感器共同计算替代。下面是具体的用法:
①首先分别获得加速度传感器和地磁传感器的实例,并给它们注册监听器:
Sensor magneticSensor=sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
Sensor accelerometerSensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(listener,magneticSensor,SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(listener,accelerometerSensor,SensorManager.SENSOR_DELAY_GAME);
②接下来再onSensorChanged()方法中可以获取到SensorEvent的values数组,分别记录着加速度传感器和地磁传感器的值。然后将这两个值传入到SensorManager的getRotationMatrix()方法中就可以得到一个包含旋转矩阵的R数组。
SensorManager.getRotationMatrix(R,null,accelerometerValues,magneticValues);
其中第一个参数R是一个长度为9的float数组,getRotationMatrix()方法计算出的旋转矩阵数据就会赋值到这个数组当中。第二个参数是一个用于将地磁向量转换成重力坐标的旋转矩阵,通常指定null即可。第三个和第四个参数分别是加速度传感器和地磁传感器的values值。
③得到R数组之后,就可以调用SensorManager的getOrientation()方法来计算手机的旋转数据了。
SensorManager.getOrientation(R,values);
values是一个长度为3的float数组,其中values[0]记录手机围绕Z轴的旋转弧度,values[1]记录手机围绕X轴的旋转弧度,values[2]记录手机围绕Y轴的旋转弧度。
注意这里计算出的数据是弧度,如果要转换为角度,则调用下面方法:
Math.toDegrees(values[0])
values[0]的取值范围是-180°到180°,其中±180°表示正南方向,0°表示正北方向,-90°表示正西方向,90°表示正东方向。
我们自己画一个简单的指南针MyCompassView,继承SurfaceView
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/** * Created by Administrator on 2015/9/21. */
public class MyCompassView extends SurfaceView {
private int width;
private int height;
private Paint paint_circle;
private Paint paint_line;
private Paint paint_text;
private String[] direction = {"E","S", "W","N"};
private float degree;
private boolean isRunning=true;
public void setDegree(float degree) {
this.degree = degree;
}
public MyCompassView(Context context) {
super(context);
}
public MyCompassView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(callback);
paint_circle = new Paint();
paint_circle.setColor(Color.GREEN);//画笔颜色
paint_circle.setStrokeWidth(10);//画笔粗细
paint_circle.setStyle(Paint.Style.STROKE);//空心
paint_circle.setAntiAlias(true);//设置抗锯齿
paint_line = new Paint();
paint_line.setColor(Color.RED);
paint_line.setStrokeWidth(15);
paint_line.setAntiAlias(true);
paint_text = new Paint();
paint_text.setColor(Color.YELLOW);
paint_text.setTextSize(50);
paint_text.setAntiAlias(true);
paint_text.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
}
SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(final SurfaceHolder holder) {//此处开启线程
new Thread(new Runnable() {
@Override
public void run() {
while (isRunning) {
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.BLUE);
canvas.drawCircle(width / 2, height / 2, 300, paint_circle);
canvas.save();
canvas.rotate(degree, width / 2, height / 2);
for (int i = 1; i <= 4; i++) {
canvas.save();
canvas.rotate(360 / 4 * i, width / 2, height / 2);
canvas.drawText(direction[i - 1], width / 2, height / 2 - 250, paint_text);
canvas.restore();
}
canvas.drawCircle(width / 2, height / 2, 50, paint_line);
Path path=new Path();
path.moveTo(width/2-50,height/2);
path.lineTo(width/2+50,height/2);
path.lineTo(width/2,height/2-200);
path.close();
canvas.drawPath(path,paint_line);
canvas.drawText(-(int)(degree)+"°",width/2,height/2,paint_text);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
}
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
holder.setFixedSize(width,height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {//关闭线程
isRunning=false;
}
};
}
然后加入到我们的布局中:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<com.example.administrator.mycompass.MyCompassView android:id="@+id/mycompassview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true"/>
</RelativeLayout>
最后是我们主活动中的代码:
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;
public class MainActivity extends AppCompatActivity {
private SensorManager sensorManager;
private MyCompassView myCompassView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myCompassView= (MyCompassView) findViewById(R.id.mycompassview);
sensorManager= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor magneticSensor=sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
Sensor accelerometerSensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(listener,magneticSensor,SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(listener,accelerometerSensor,SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (sensorManager!=null){
sensorManager.unregisterListener(listener);
}
}
private SensorEventListener listener=new SensorEventListener() {
float[] accelerometerValues=new float[3];
float[] magneticValues=new float[3];
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
accelerometerValues=event.values.clone();
}else if (event.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD){
magneticValues=event.values.clone();
}
float[] R=new float[9];
float[] values=new float[3];
SensorManager.getRotationMatrix(R,null,accelerometerValues,magneticValues);
SensorManager.getOrientation(R,values);
float degree= -(float) Math.toDegrees(values[0]);//旋转角度
myCompassView.setDegree(degree);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
}