一.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)
       应用:手机接电话时屏幕熄屏

(六)光线传感器的一些值的标准

  1. 最强的光线强度(估计只有沙漠地带才能达到这个值)
    public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
    2.万里无云时阳光直射的强度
    public static final float LIGHT_SUNLIGHT = 110000.0f;
  2. 有阳光,但被云彩抵消了部分光线时的强度
    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个或更多。

手机模拟器的显示情况:

android传感器应用程序 android常用传感器有哪些_android

真机显示情况:

android传感器应用程序 android常用传感器有哪些_传感器_02

       另外在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);
    }

}

       传感器的测试要在真机中运行。

       程序运后显示的界面:

android传感器应用程序 android常用传感器有哪些_数据_03


当手机往右边和下边倾斜后显示的效果:

       

android传感器应用程序 android常用传感器有哪些_Android_04


       但手机向某一个方向倾斜,小球就会想某个方向去滑动,这里小球没有设置边界,所以小球会滑出屏幕外面,想要设置其实也是很简单的,在MyView里面设置就可以了。

       关于Android传感器的使用并不是很多,一般的学会使用加速度传感器和方向传感器就可以了。而且使用它们都是不用添加权限的。