Android 传感器

image.png
加速传感器
public class MainActivity extends AppCompatActivity implements SensorEventListener {
    // 定义系统的Sensor管理器
    private SensorManager sensorManager;
    private TextView etTxt1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取程序界面上的文本框组件
        etTxt1 = findViewById(R.id.txt1);
        // 获取系统的传感器管理服务
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);  // ①
    }

    @Override
    public void onResume() {
        super.onResume();
         
        /*
         * 为系统的加速度传感器注册监听器
         *
         * SENSOR_DELAY_FASTEST 最快。延迟最小,只有特别依赖于传感器数据的应用推荐采用这种频率,该种模式可能造成手机电量大量消耗。由于传递的为原始数据,算法处理不好将会影响应用的性能。
         * SENSOR_DELAY_GAME 适合游戏的频率。一般有实时性要求的应用适合使用这种频率
         * SENSOR_DELAY_NORMAL 正常频率。一般对实时性要求不是特别高的应用适合使用这种频率。
         * SENSOR_DELAY_UI 适合普通用户界面的频率。这种模式比较省电,而且系统开销也很小,但延迟较大,因此只适合在普通小程序中使用。
         * */
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(
                        Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_UI); // ②
    }

    @Override
    public void onPause() {
        super.onPause();
        // 取消注册
        sensorManager.unregisterListener(this);
    }

    // 以下是实现SensorEventListener接口必须实现的方法
    // 当传感器的值发生改变时回调该方法
    @Override
    public void onSensorChanged(SensorEvent event) {
        float[] values = event.values;
        String sb = "X方向上的加速度:" +
                values[0] +
                "\nY方向上的加速度:" +
                values[1] +
                "\nZ方向上的加速度:" +
                values[2];
        etTxt1.setText(sb);
    }

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

常用传感器

public class MainActivity extends AppCompatActivity implements SensorEventListener {
    // 定义Sensor管理器
    private SensorManager mSensorManager;
    private TextView etOrientation;
    private TextView etGyro;
    private TextView etMagnetic;
    private TextView etGravity;
    private TextView etLinearAcc;
    private TextView etTemerature;
    private TextView etHumidity;
    private TextView etLight;
    private TextView etPressure;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取界面上的TextView组件
        etOrientation = findViewById(R.id.etOrientation);
        etGyro = findViewById(R.id.etGyro);
        etMagnetic = findViewById(R.id.etMagnetic);
        etGravity = findViewById(R.id.etGravity);
        etLinearAcc = findViewById(R.id.etLinearAcc);
        etTemerature = findViewById(R.id.etTemerature);
        etHumidity = findViewById(R.id.etHumidity);
        etLight = findViewById(R.id.etLight);
        etPressure = findViewById(R.id.etPressure);
        // 获取传感器管理服务
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);  // ①
    }

    @Override
    public void onResume() {
        super.onResume();
        // 为系统的方向传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的陀螺仪传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的磁场传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的重力传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的线性加速度传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的温度传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的湿度传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的光传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
                SensorManager.SENSOR_DELAY_GAME);
        // 为系统的压力传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
                SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    public void onPause() {
        // 程序暂停时取消注册传感器监听器
        mSensorManager.unregisterListener(this);
        super.onPause();
    }

    // 以下是实现SensorEventListener接口必须实现的方法
    // 当传感器精度改变时回调该方法
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float[] values = event.values;
        // 获取触发event的传感器类型
        int sensorType = event.sensor.getType();
        StringBuilder sb;
        // 判断是哪个传感器发生改变
        switch (sensorType) {
            // 方向传感器
            case Sensor.TYPE_ORIENTATION:
                sb = new StringBuilder();
                sb.append("绕Z轴转过的角度:");
                sb.append(values[0]);
                sb.append("\n绕X轴转过的角度:");
                sb.append(values[1]);
                sb.append("\n绕Y轴转过的角度:");
                sb.append(values[2]);
                etOrientation.setText(sb.toString());
                break;
            // 陀螺仪传感器
            case Sensor.TYPE_GYROSCOPE:
                sb = new StringBuilder();
                sb.append("绕X轴旋转的角速度:");
                sb.append(values[0]);
                sb.append("\n绕Y轴旋转的角速度:");
                sb.append(values[1]);
                sb.append("\n绕Z轴旋转的角速度:");
                sb.append(values[2]);
                etGyro.setText(sb.toString());
                break;
            // 磁场传感器
            case Sensor.TYPE_MAGNETIC_FIELD:
                sb = new StringBuilder();
                sb.append("X轴方向上的磁场强度:");
                sb.append(values[0]);
                sb.append("\nY轴方向上的磁场强度:");
                sb.append(values[1]);
                sb.append("\nZ轴方向上的磁场强度:");
                sb.append(values[2]);
                etMagnetic.setText(sb.toString());
                break;
            // 重力传感器
            case Sensor.TYPE_GRAVITY:
                sb = new StringBuilder();
                sb.append("X轴方向上的重力:");
                sb.append(values[0]);
                sb.append("\nY轴方向上的重力:");
                sb.append(values[1]);
                sb.append("\nZ轴方向上的重力:");
                sb.append(values[2]);
                etGravity.setText(sb.toString());
                break;
            // 线性加速度传感器
            case Sensor.TYPE_LINEAR_ACCELERATION:
                sb = new StringBuilder();
                sb.append("X轴方向上的线性加速度:");
                sb.append(values[0]);
                sb.append("\nY轴方向上的线性加速度:");
                sb.append(values[1]);
                sb.append("\nZ轴方向上的线性加速度:");
                sb.append(values[2]);
                etLinearAcc.setText(sb.toString());
                break;
            // 温度传感器
            case Sensor.TYPE_AMBIENT_TEMPERATURE:
                sb = new StringBuilder();
                sb.append("当前温度为:");
                sb.append(values[0]);
                etTemerature.setText(sb.toString());
                break;
            // 湿度传感器
            case Sensor.TYPE_RELATIVE_HUMIDITY:
                sb = new StringBuilder();
                sb.append("当前湿度为:");
                sb.append(values[0]);
                etHumidity.setText(sb.toString());
                break;
            // 光传感器
            case Sensor.TYPE_LIGHT:
                sb = new StringBuilder();
                sb.append("当前光的强度为:");
                sb.append(values[0]);
                etLight.setText(sb.toString());
                break;
            // 压力传感器
            case Sensor.TYPE_PRESSURE:
                sb = new StringBuilder();
                sb.append("当前压力为:");
                sb.append(values[0]);
                etPressure.setText(sb.toString());
                break;
        }
    }
}

实例:指南针

public class MainActivity extends AppCompatActivity implements SensorEventListener {
    // 定义显示指南针的图片
    private ImageView znzIV;
    // 记录指南针图片转过的角度
    private float currentDegree = 0f;
    // 定义Sensor管理器
    private SensorManager mSensorManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        znzIV = findViewById(R.id.znzImage);
        // 获取传感器管理服务
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onResume() {
        super.onResume();
        // 为系统的方向传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    public void onPause() {
        // 取消注册
        mSensorManager.unregisterListener(this);
        super.onPause();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // 获取触发event的传感器类型
        int sensorType = event.sensor.getType();
        switch (sensorType) {
            case Sensor.TYPE_ORIENTATION:
                // 获取绕Z轴转过的角度
                float degree = event.values[0];
                // 创建旋转动画(反向转过degree度)
                RotateAnimation ra = new RotateAnimation(currentDegree, -degree,
                        Animation.RELATIVE_TO_SELF, 0.5f,
                        Animation.RELATIVE_TO_SELF, 0.5f);
                // 设置动画的持续时间
                ra.setDuration(200);
                // 运行动画
                znzIV.startAnimation(ra);
                currentDegree = -degree;
                break;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}
image.png

实例:水平仪

MyView

public class MyView extends View {
    // 定义水平仪仪表盘图片
    Bitmap back;
    // 定义水平仪中的气泡图标
    Bitmap bubble;
    // 定义水平仪中气泡的X、Y坐标
    float bubbleX = 0f;
    float bubbleY = 0f;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取窗口管理器
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        // 获取屏幕的宽度和高度
        Display display = wm.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        int screenWidth = metrics.widthPixels;
        // 创建位图
        back = Bitmap.createBitmap(screenWidth, screenWidth,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(back);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        // 设置绘制风格:仅填充
        paint.setStyle(Paint.Style.FILL);
        // 创建一个线性渐变来绘制线性渐变
        LinearGradient shader = new LinearGradient(0f, screenWidth, screenWidth * 0.8f,
                screenWidth * 0.2f, Color.YELLOW, Color.WHITE, Shader.TileMode.MIRROR);
        paint.setShader(shader);
        // 绘制圆形
        canvas.drawCircle(screenWidth / 2, screenWidth / 2, screenWidth / 2, paint);
        Paint paint2 = new Paint();
        paint2.setAntiAlias(true);
        // 设置绘制风格:仅绘制边框
        paint2.setStyle(Paint.Style.STROKE);
        paint2.setStrokeWidth(5f);  // 设置画笔宽度
        paint2.setColor(Color.BLACK); // 设置画笔颜色
        // 绘制圆形边框
        canvas.drawCircle(screenWidth / 2, screenWidth / 2, screenWidth / 2, paint2);
        // 绘制水平横线
        canvas.drawLine(0f, screenWidth / 2, screenWidth, screenWidth / 2, paint2);
        // 绘制垂直横线
        canvas.drawLine(screenWidth / 2, 0f, screenWidth / 2, screenWidth, paint2);
        paint2.setStrokeWidth(10f);  // 设置画笔宽度
        // 设置画笔颜色
        paint2.setColor(Color.RED);
        // 绘制中心的红色“十”字
        canvas.drawLine(screenWidth / 2 - 30, screenWidth / 2,
                screenWidth / 2 + 30, screenWidth / 2, paint2);
        canvas.drawLine(screenWidth / 2, screenWidth / 2 - 30,
                screenWidth / 2, screenWidth / 2 + 30, paint2);
        // 加载气泡图片
        bubble = BitmapFactory.decodeResource(getResources(), R.drawable.bubble);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制水平仪仪表盘图片
        canvas.drawBitmap(back, 0f, 0f, null);
        // 根据气泡坐标绘制气泡
        canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
    }
}
public class MainActivity extends AppCompatActivity implements SensorEventListener {
    public final static int MAX_ANGLE = 30;
    // 定义水平仪的仪表盘
    private MyView show;
    // 定义Sensor管理器
    private SensorManager mSensorManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取水平仪的主组件
        show = findViewById(R.id.show);
        // 获取传感器管理服务
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onResume() {
        super.onResume();
        // 为系统的方向传感器注册监听器
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    public void onPause() {
        // 取消注册
        mSensorManager.unregisterListener(this);
        super.onPause();
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float[] values = event.values;
        // 获取触发event的传感器类型
        int sensorType = event.sensor.getType();
        switch (sensorType) {
            case Sensor.TYPE_ORIENTATION:
                // 获取与Y轴的夹角
                float yAngle = values[1];
                // 获取与Z轴的夹角
                float zAngle = values[2];
                // 气泡位于中间时(水平仪完全水平),气泡的X、Y坐标
                float x = (show.back.getWidth() - show.bubble.getWidth()) / 2;
                float y = (show.back.getHeight() - show.bubble.getHeight()) / 2;
                // 如果与Z轴的倾斜角还在最大角度之内
                if (Math.abs(zAngle) <= MAX_ANGLE) {
                    // 根据与Z轴的倾斜角度计算X坐标的变化值
                    // (倾斜角度越大,X坐标变化越大)
                    int deltaX = (int) ((show.back.getWidth() - show.bubble
                            .getWidth()) / 2 * zAngle / MAX_ANGLE);
                    x += deltaX;
                }
                // 如果与Z轴的倾斜角已经大于MAX_ANGLE,气泡应到最左边
                else if (zAngle > MAX_ANGLE) {
                    x = 0;
                }
                // 如果与Z轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边
                else {
                    x = show.back.getWidth() - show.bubble.getWidth();
                }
                // 如果与Y轴的倾斜角还在最大角度之内
                if (Math.abs(yAngle) <= MAX_ANGLE) {
                    // 根据与Y轴的倾斜角度计算Y坐标的变化值
                    // (倾斜角度越大,Y坐标变化越大)
                    int deltaY = (int) ((show.back.getHeight() - show.bubble
                            .getHeight()) / 2 * yAngle / MAX_ANGLE);
                    y += deltaY;
                }
                // 如果与Y轴的倾斜角已经大于MAX_ANGLE,气泡应到最下边
                else if (yAngle > MAX_ANGLE) {
                    y = show.back.getHeight() - show.bubble.getHeight();
                }
                // 如果与Y轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最上边
                else {
                    y = 0;
                }
                // 如果计算出来的X、Y坐标还位于水平仪的仪表盘内,更新水平仪的气泡坐标
                if (isContain(x, y)) {
                    show.bubbleX = x;
                    show.bubbleY = y;
                }
                // 通知系统重绘MyView组件
                show.postInvalidate();
                break;
        }
    }

    // 计算x、y点的气泡是否处于水平仪的仪表盘内
    private boolean isContain(float x, float y) {
        // 计算气泡的圆心坐标X、Y
        float bubbleCx = x + show.bubble.getWidth() / 2;
        float bubbleCy = y + show.bubble.getHeight() / 2;
        // 计算水平仪仪表盘的圆心坐标X、Y
        float backCx = show.back.getWidth() / 2;
        float backCy = show.back.getHeight() / 2;
        // 计算气泡的圆心与水平仪仪表盘的圆心之间的距离
        double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx) +
                (bubbleCy - backCy) * (bubbleCy - backCy));
        // 若两个圆心的距离小于它们的半径差,即可认为处于该点的气泡依然位于仪表盘内
        return distance < (show.back.getWidth() - show.bubble.getWidth()) / 2;
    }
}
image.png

摘抄至《疯狂Android讲义(第4版)》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容