光照传感器
Android 中每个传感器的用法其实都比较类似,真的可以说是一通百通了。首先第一步要获取到 SensorManager 的实例
SensorManager senserManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor sensor = senserManager.getDefaultSensor(Sensor.TYPE_LIGHT);
SensorEventListener listener = new SensorEventListener() { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { } };
senserManager.registerListener(listener, senser, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.unregisterListener(listener);
public class MainActivity extends Activity { SensorManager sensorManager; TextView light; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); light=(TextView) findViewById(R.id.textView1); sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE); Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); sensorManager.registerListener(null, sensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (sensorManager!=null) { sensorManager.unregisterListener(listener); } } private SensorEventListener listener=new SensorEventListener() { @Override public void onSensorChanged(SensorEvent arg0) { // TODO Auto-generated method stub // values数组中第一个下标的值就是当前的光照强度 float value=arg0.values[0]; light.setText("Current light level is"+value+"lx"); } @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } };
现在运行一下程序, 你将会在手机上看到当前环境下的光照强度, 根据所处环境的不同,显示的数值有可能是几十到几百勒克斯。而如果你使用强光来照射手机的话,就有可能会达到上千勒克斯的光照强度
加速度传感器:
第一, 获取 Sensor 实例的时候要指定一个加速度传感器的常量, 如下所示:
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
第二,加速度传感器输出的信息同样也是存放在 SensorEvent 的 values 数组中的,只不过此时的 values 数组中会有三个值,分别代表手机在 X 轴、Y 轴和 Z 轴方向上的加速度信息。X 轴、Y 轴、Z 轴在空间坐标系上的含义需要注意的是,由于地心引力的存在,你的手机无论在世界上任何角落都会有一个重力加速度,这个加速度的值大约是 9.8m/s
2 。当手机平放的时候,这个加速度是作用在 Z 轴上的,当手机竖立起来的时候,这个加速度是作用在 Y 轴上的,当手机横立起来的时候,这个加速度是作用在 X 轴上的
模仿微信摇一摇
package com.example.yaoyiyao; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.view.Menu; import android.widget.Toast; public class MainActivity extends Activity { private SensorManager sensorManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE); Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (sensorManager!=null) { sensorManager.unregisterListener(sensorEventListener); } } private SensorEventListener sensorEventListener=new SensorEventListener() { @Override public void onSensorChanged(SensorEvent arg0) { // TODO Auto-generated method stub // 加速度可能会是负值,所以要取它们的绝对值 float xValue=Math.abs(arg0.values[0]); float yValue=Math.abs(arg0.values[1]); float zValue=Math.abs(arg0.values[2]); if (xValue>15||yValue>15||zValue>15) { // 认为用户摇动了手机,触发摇一摇逻辑 Toast.makeText(MainActivity.this, "摇一摇", Toast.LENGTH_SHORT).show(); } } @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } }; }
方向传感器:
我们需要获取到一个用于表示方向传感器的 Sensor 实例
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
其中,values[0]记录着手机围绕 Z 轴的旋转角度,values[1] 记录着手机围绕 X 轴的旋转角度,values[2] 记录着手机围绕 Y 轴的旋转角度
看起来很美好是吗?但遗憾的是, Android早就废弃了Sensor.TYPE_ORIENTATION这种传感器类型,虽然代码还是有效的,但已经不再推荐这么写了。事实上,Android 获
取手机旋转的方向和角度是通过加速度传感器和地磁传感器共同计算得出的,这也是Android 目前推荐使用的方式。首先我们需要分别获取到加速度传感器和地磁传感器的实例,并给它们注册监听器
Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor. TYPE_ACCELEROMETER); Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor. TYPE_MAGNETIC_FIELD); sensorManager.registerListener(listener, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME); sensorManager.registerListener(listener, magneticSensor, SensorManager.SENSOR_DELAY_GAME);
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);
SensorManager.getOrientation(R, values)alues 是一个长度为 3 的 float 数组,手机在各个方向上的旋转数据都会被存放到这个数组当中。其中 values[0]记录着手机围绕着图 12.3 中 Z 轴的旋转弧度,values[1]记录
简易指南针
package com.example.zhinanzhen; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.util.Log; import android.view.Menu; public class MainActivity extends Activity { private SensorManager sensorManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE); //磁性传感器 Sensor magmagneticSensor=sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); //加速度传感器 Sensor accelerometerSensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(listener, magmagneticSensor, SensorManager.SENSOR_DELAY_GAME); } @Override protected void onDestroy() { // TODO Auto-generated method stub 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 arg0) { // TODO Auto-generated method stub // 判断当前是加速度传感器还是地磁传感器 if (arg0.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 注意赋值时要调用clone()方法 accelerometerValues = arg0.values.clone(); } else if (arg0.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { // 注意赋值时要调用clone()方法 magneticValues = arg0.values.clone(); } float[] R = new float[9]; float[] values = new float[3]; SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues); SensorManager.getOrientation(R, values); Log.d("MainActivity", "value[0] is " + Math.toDegrees(values[0])); } @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } }; }
alues[0]的取值范围是- 180 度到 180 度,其中±180 度表示正南方向,0 度表示正北方向,- 90 度表示正西方向,90 度表示正东方向。虽然目前我们已经得到了这些数值, 但是想要通过它们来判断手机当前的方向显然是一件伤脑筋的事情,因此我们还要想办法将当前的方向直观地显示出来。毫无疑问,最直观的方式当然是通过罗盘和指针来进行显示了,那么下面我们就来继续完善 CompassTest这个项目。这里我事先准备好了两张图片 compass.png 和 arrow.png,分别用于作为指南针的
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/compass_img" android:layout_width="250dp" android:layout_height="250dp" android:layout_centerInParent="true" android:src="@drawable/compass" /> <ImageView android:id="@+id/arrow_img" android:layout_width="60dp" android:layout_height="110dp" android:layout_centerInParent="true" android:src="@drawable/arrow" /> </RelativeLayout>
public class MainActivity extends Activity { private SensorManager sensorManager; private ImageView compassImg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); compassImg = (ImageView) findViewById(R.id.compass_img); ⋯⋯ } ⋯⋯ private SensorEventListener listener = new SensorEventListener() { float[] accelerometerValues = new float[3]; float[] magneticValues = new float[3]; private float lastRotateDegree; @Override public void onSensorChanged(SensorEvent event) { // 判断当前是加速度传感器还是地磁传感器 if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 注意赋值时要调用clone()方法 accelerometerValues = event.values.clone(); } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { // 注意赋值时要调用clone()方法 magneticValues = event.values.clone(); } float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues); SensorManager.getOrientation(R, values); // 将计算出的旋转角度取反,用于旋转指南针背景图 float rotateDegree = -(float) Math.toDegrees(values[0]); if (Math.abs(rotateDegree - lastRotateDegree) > 1) { 第 12 章 Android 特色开发,使用传感器 473 RotateAnimation animation = new RotateAnimation (lastRotateDegree, rotateDegree, Animation.RELATIVE_TO_SELF, 0.5f, Animation. RELATIVE_TO_SELF, 0.5f); animation.setFillAfter(true); compassImg.startAnimation(animation); lastRotateDegree = rotateDegree; } } ⋯⋯ }; }
这里首先我们在 onCreate()方法中获取到了 ImageView 的实例,它是用于显示指南针的背景图的。然后在 onSensorChanged()方法中使用到了旋转动画技术,我们创建了一
个 RotateAnimation 的实例,并给它的构造方法传入了六个参数,第一个参数表示旋转的起始角度,第二个参数表示旋转的终止角度,后面四个参数用于指定旋转的中心点。这里我们把从传感器中获取到的旋转角度取反,传递给 RotateAnimation,并指定旋转的中心点为指南针背景图的中心,然后调用 ImageView 的 startAnimation ()方法来执行旋转动画。好了,代码就是这么多,现在我们重新运行一下程序,然后随意旋转手机,指南针的背景图也会跟着一起转动