Android开发笔记(五十九)巧用传感器

传感器Sensor

传感器是Android用来感知周围环境以及运动信息的工具。因为具体的感应信息依赖于相关硬件,所以虽然Android提供了众多的感应器,但不是每部手机都能支持这么多感应器,恰恰相反,大多数安卓手机仅仅支持包括加速度在内的少数几个感应器。 传感器借助于硬件来监听环境改变的事件,从这个意义上来说,Android的事件都是由某个传感器触发,只不过这个触发来源可能是软件,也可能是屏幕,甚至可能是手机的sim卡。回顾一下之前的事件通信章节,我们会发现,原来它们在本质上跟传感器是类似的,比如说: 1、软件感应:UI事件(参见《Android开发笔记(四十四)动态UI事件》)、媒体播放事件(参见《Android开发笔记(五十七)录像录音与播放》)、浏览器加载、交互与下载事件(参见《Android开发笔记(六十四)网页加载与JS调用》)。 2、屏幕感应:点击事件(参见《Android开发笔记(四十三)点击事件》)、手势事件(参见《Android开发笔记(四十五)手势事件》)、拖动条的拖动事件(参见《Android开发笔记(五十八)铃声与震动》)。 3、sim卡感应:手机相关事件(参见《Android开发笔记(四十六)手机相关事件》)。 4、摄像头感应:拍照事件(参见《Android开发笔记(五十六)摄像头拍照》)。 5、麦克风感应:录音事件(参见《Android开发笔记(五十七)录像录音与播放》)。 6、系统感应:电量事件、屏幕开关事件(参见《Android开发笔记(一百一十七)app省电方略》)。 下面是目前Android支持的感应器类型: 1 TYPE_ACCELEROMETER //加速度 2 TYPE_MAGNETIC_FIELD //磁场 3 TYPE_ORIENTATION //方向,该类型已弃用,取而代之的是getOrientation方法 4 TYPE_GYROSCOPE //陀螺仪 5 TYPE_LIGHT //光线 6 TYPE_PRESSURE //压力 7 TYPE_TEMPERATURE //温度,该类型已弃用,取而代之的是TYPE_AMBIENT_TEMPERATURE 8 TYPE_PROXIMITY //距离 9 TYPE_GRAVITY //重力 10 TYPE_LINEAR_ACCELERATION //线性加速度 11 TYPE_ROTATION_VECTOR //旋转矢量 12 TYPE_RELATIVE_HUMIDITY //湿度 13 TYPE_AMBIENT_TEMPERATURE //环境温度 14 TYPE_MAGNETIC_FIELD_UNCALIBRATED //无标定磁场 15 TYPE_GAME_ROTATION_VECTOR //无标定旋转矢量 16 TYPE_GYROSCOPE_UNCALIBRATED //未校准陀螺仪 17 TYPE_SIGNIFICANT_MOTION //特殊动作 18 TYPE_STEP_DETECTOR //步行检测,用户每走一步就触发一次事件 19 TYPE_STEP_COUNTER //计步器,记录激活后的步伐数 20 TYPE_GEOMAGNETIC_ROTATION_VECTOR //地磁旋转矢量

加速度感应器/摇一摇

这个功能最有名的应用就是微信里的“摇一摇”了,用户通过摇晃手机来寻找周围的人;类似的业务还有摇奖、玩游戏等等。

下面以摇一摇的实现来演示传感器开发的步骤:

1、声明一个SensorManager对象,该对象从系统服务Context.SENSOR_SERVICE中获取实例; 2、编写一个传感器事件监听器,该监听器继承自SensorEventListener,同时需实现onSensorChanged和onAccuracyChanged两个方法。其中前一个方法在感应变化时触发,业务逻辑都在这边处理;后一个方法在精度改变时触发,一般无需处理。 3、重写onResume方法,在该方法中注册传感器监听事件,使用的是registerListener方法,该方法的第二个参数为Sensor类型,须调用SensorManager对象的getDefaultSensor来获取指定类型的传感器对象。例如摇一摇功能要注册加速度感应监听器,代码示例如下:

		mSensroMgr.registerListener(this,
				mSensroMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_NORMAL);

4、重写onPause方法,在该方法中注销传感器事件,代码示例如下:

		mSensroMgr.unregisterListener(this);

下面是摇一摇功能的核心代码:

			float[] values = event.values;
			if (sensorType == Sensor.TYPE_ACCELEROMETER) {
				if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15 
						|| Math.abs(values[2]) > 15)) {
					tv_shake.setText(getNowDateTime()+" 恭喜您摇一摇啦");
					//系统检测到摇一摇事件后,震动手机提示用户
					mVibrator.vibrate(500);
				}
			}

前置摄像头的感应

博主的手机比较廉价,支持的感应器不多,除了加速度之外,就只有光线与距离感应器了。不过很奇怪,距离感应器只能探测到0-1厘米的距离,不会探测到2厘米以上的距离。于是好好琢磨了下,发现只有遮挡手机上面扬声器与前置摄像头所在的位置,距离感应才会变化,遮挡屏幕其余地方,距离感应并无变化。同样的,光线感应也是如此,把手机上部遮住,光线强度一下就降得很低。据此,我推测,光线与距离很可能是依靠前置摄像头来感应,所以一旦遮住前置摄像头,光线与距离感应马上就被触发了。

代码示例

下面是摇一摇、光线与距离感应的效果截图:

下面是传感器开发(摇一摇)的完整代码例子:

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.widget.TextView;

import com.example.exmcamera.R;

public class SensorActivity extends Activity implements SensorEventListener {

	private static final String TAG = "SensorActivity";
	private TextView tv_sensor;
	private TextView tv_shake;
	private TextView tv_light;
	private TextView tv_distance;
	private SensorManager mSensroMgr;
	private Vibrator mVibrator;
	private String[] mSensorType = {
			"加速度", "磁场", "方向", "陀螺仪", "光线", 
			"压力", "温度", "距离", "重力", "线性加速度", 
			"旋转矢量", "湿度", "环境温度", "无标定磁场", "无标定旋转矢量", 
			"未校准陀螺仪", "特殊动作", "步行检测", "计步器", "地磁旋转矢量"};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sensor);

		tv_sensor = (TextView) findViewById(R.id.tv_sensor);
		tv_shake = (TextView) findViewById(R.id.tv_shake);
		tv_light = (TextView) findViewById(R.id.tv_light);
		tv_distance = (TextView) findViewById(R.id.tv_distance);
		mSensroMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		showSensorInfo();
	}

	private void showSensorInfo() {
		List<Sensor> sensorList = mSensroMgr.getSensorList(Sensor.TYPE_ALL);
		ArrayList<String> sensorNameList = new ArrayList<String>();
		String show_content = "当前支持的传感器包括:\n";
		for (Sensor sensor : sensorList) {
			sensorNameList.add(sensor.getName());
			String content = String.format("%s:%s\n", 
					mSensorType[sensor.getType()-1], sensor.getName());
			show_content += content;
		}
		tv_sensor.setText(show_content);
	}

	private String getNowDateTime() {
		SimpleDateFormat s_format = new SimpleDateFormat("HH:mm:ss");
		Date d_date = new Date();
		String s_date = "";
		s_date = s_format.format(d_date);
		return s_date;
	}

	@Override
	protected void onPause() {
		super.onPause();
		mSensroMgr.unregisterListener(this);
	}

	@Override
	protected void onResume() {
		super.onResume();
		mSensroMgr.registerListener(this,
				mSensroMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_NORMAL);
		mSensroMgr.registerListener(this,
				mSensroMgr.getDefaultSensor(Sensor.TYPE_LIGHT),
				SensorManager.SENSOR_DELAY_NORMAL);
		mSensroMgr.registerListener(this,
				mSensroMgr.getDefaultSensor(Sensor.TYPE_PROXIMITY),
				SensorManager.SENSOR_DELAY_NORMAL);
	}
  
	@Override
	public void onSensorChanged(SensorEvent event) {
		int sensorType = event.sensor.getType();
		if (sensorType == Sensor.TYPE_ACCELEROMETER) {
			// values[0]:X轴,values[1]:Y轴,values[2]:Z轴
			float[] values = event.values;
			if (sensorType == Sensor.TYPE_ACCELEROMETER) {
				if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15 
						|| Math.abs(values[2]) > 15)) {
					tv_shake.setText(getNowDateTime()+" 恭喜您摇一摇啦");
					//系统检测到摇一摇事件后,震动手机提示用户
					mVibrator.vibrate(500);
				}
			}
		} else if (sensorType == Sensor.TYPE_LIGHT) {
			float light_strength = event.values[0];
			tv_light.setText(getNowDateTime()+" 当前光线强度为"+light_strength);
		} else if (sensorType == Sensor.TYPE_PROXIMITY) {
			float distance = event.values[0];
			tv_distance.setText(getNowDateTime()+" 有不明物体接近!距离"+distance+"厘米");
		}
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		//当传感器精度改变时回调该方法,一般无需处理
	}
	
}

点击下载本文用到的传感器操作的工程代码 点此查看Android开发笔记的完整目录

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券