【Android App】物联网中指南针、计步器、感光器、陀螺仪的讲解及实战演示(附源码 超详细必看)

简介: 【Android App】物联网中指南针、计步器、感光器、陀螺仪的讲解及实战演示(附源码 超详细必看)

需要源码请点赞关注收藏后评论区留言~~~

一、指南针-磁场传感器

顾名思义,指南针只要找到朝南的方向就好了。 可是在App中并非使用一个方向传感器这么简单,事实上单独的方向传感器已经弃用,取而代之的是利用加速度传感器和磁场传感器。 获得加速度和磁场强度两个数值之后,再通过SensorManager的getRotationMatrix方法与getOrientation方法计算方向角度。

要想在手机上模拟指南针的效果,需要自己编写一个罗盘视图,然后在罗盘上绘制正南方向的指针效果如下  晃动手机头部即会显示不同方向

代码如下

package com.example.iot;
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.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.iot.widget.CompassView;
import java.util.List;
public class DirectionActivity extends AppCompatActivity implements SensorEventListener {
    private TextView tv_direction; // 声明一个文本视图对象
    private CompassView cv_sourth; // 声明一个罗盘视图对象
    private SensorManager mSensorMgr;// 声明一个传感管理器对象
    private float[] mAcceValues; // 加速度变更值的数组
    private float[] mMagnValues; // 磁场强度变更值的数组
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_direction);
        tv_direction = findViewById(R.id.tv_direction);
        cv_sourth = findViewById(R.id.cv_sourth);
        // 从系统服务中获取传感管理器对象
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }
    @Override
    protected void onPause() {
        super.onPause();
        mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器
    }
    @Override
    protected void onResume() {
        super.onResume();
        int suitable = 0;
        // 获取当前设备支持的传感器列表
        List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor : sensorList) {
            if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 找到加速度传感器
                suitable += 1; // 找到加速度传感器
            } else if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { // 找到磁场传感器
                suitable += 10; // 找到磁场传感器
            }
        }
        if (suitable / 10 > 0 && suitable % 10 > 0) {
            // 给加速度传感器注册传感监听器
            mSensorMgr.registerListener(this,
                    mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
            // 给磁场传感器注册传感监听器
            mSensorMgr.registerListener(this,
                    mSensorMgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);
        } else {
            cv_sourth.setVisibility(View.GONE);
            tv_direction.setText("当前设备不支持指南针,请检查是否存在加速度和磁场传感器");
        }
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 加速度变更事件
            mAcceValues = event.values; // 加速度变更事件
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { // 磁场强度变更事件
            mMagnValues = event.values; // 磁场强度变更事件
        }
        if (mAcceValues != null && mMagnValues != null) {
            calculateOrientation(); // 加速度和磁场强度两个都有了,才能计算磁极的方向
        }
    }
    //当传感器精度改变时回调该方法,一般无需处理
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    // 计算指南针的方向
    private void calculateOrientation() {
        float[] values = new float[3];
        float[] R = new float[9];
        SensorManager.getRotationMatrix(R, null, mAcceValues, mMagnValues);
        SensorManager.getOrientation(R, values);
        values[0] = (float) Math.toDegrees(values[0]); // 计算手机上部与正北方向的夹角
        cv_sourth.setDirection((int) values[0]); // 设置罗盘视图中的指南针方向
        if (values[0] >= -10 && values[0] < 10) {
            tv_direction.setText("手机上部方向是正北");
        } else if (values[0] >= 10 && values[0] < 80) {
            tv_direction.setText("手机上部方向是东北");
        } else if (values[0] >= 80 && values[0] <= 100) {
            tv_direction.setText("手机上部方向是正东");
        } else if (values[0] >= 100 && values[0] < 170) {
            tv_direction.setText("手机上部方向是东南");
        } else if ((values[0] >= 170 && values[0] <= 180)
                || (values[0]) >= -180 && values[0] < -170) {
            tv_direction.setText("手机上部方向是正南");
        } else if (values[0] >= -170 && values[0] < -100) {
            tv_direction.setText("手机上部方向是西南");
        } else if (values[0] >= -100 && values[0] < -80) {
            tv_direction.setText("手机上部方向是正西");
        } else if (values[0] >= -80 && values[0] < -10) {
            tv_direction.setText("手机上部方向是西北");
        }
    }
}

二、计步器

计步器的原理是通过手机的前后摆动模拟步伐节奏的监测。Android中与计步器有关的传感器有两个。

(1)一个是步行检测(TYPE_STEP_DETECTOR) 步行检测的返回数值为1时,表示当前监测到一个步伐;

(2)另一个是步行计数(TYPE_STEP_ COUNTER) 步行计数的返回数值是累加后的数值,表示本次开机激活后的总步伐数。

效果如下  随着走路上面的计数会发生对应的变化

代码如下

package com.example.iot;
import android.annotation.SuppressLint;
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.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
@SuppressLint("DefaultLocale")
public class StepActivity extends AppCompatActivity implements SensorEventListener {
    private TextView tv_step; // 声明一个文本视图对象
    private SensorManager mSensorMgr; // 声明一个传感管理器对象
    private int mStepDetector = 0; // 累加的步行检测次数
    private int mStepCounter = 0; // 计步器统计的步伐数目
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_step);
        tv_step = findViewById(R.id.tv_step);
        initStepSensor(); // 初始化步行传感器
    }
    // 初始化步行传感器
    private void initStepSensor() {
        // 从系统服务中获取传感管理器对象
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        int suitable = 0;
        // 获取当前设备支持的传感器列表
        List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor : sensorList) {
            if (sensor.getType() == Sensor.TYPE_STEP_DETECTOR) { // 找到步行检测传感器
                suitable += 1;
                // 给步行检测传感器注册传感监听器
                mSensorMgr.registerListener(this,
                        mSensorMgr.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR),
                        SensorManager.SENSOR_DELAY_NORMAL);
            } else if (sensor.getType() == Sensor.TYPE_STEP_COUNTER) { // 找到计步器
                suitable += 10;
                // 给计步器注册传感监听器
                mSensorMgr.registerListener(this,
                        mSensorMgr.getDefaultSensor(Sensor.TYPE_STEP_COUNTER),
                        SensorManager.SENSOR_DELAY_NORMAL);
            }
        }
        if (suitable == 0) {
            tv_step.setText("当前设备不支持计步器,请检查是否存在步行检测传感器和计步器");
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) { // 步行检测事件
            if (event.values[0] == 1.0f) {
                mStepDetector++; // 步行检测事件
            }
        } else if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) { // 计步器事件
            mStepCounter = (int) event.values[0]; // 计步器事件
        }
        String desc = String.format("设备检测到您当前走了%d步,总计数为%d步",
                mStepDetector, mStepCounter);
        tv_step.setText(desc);
    }
    //当传感器精度改变时回调该方法,一般无需处理
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

三、感光器

感光器也叫光线传感器,借助于前置摄像头的曝光,一旦遮住前置摄像头,传感器监测到的光线强度立马就会降低。 在实际开发中,光线传感器往往用于感应手机正面的光线强弱,从而自动调节屏幕亮度

摄像头没有被遮挡前数值如下

被遮挡后数值如下

代码如下

package com.example.iot;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.iot.util.DateUtil;
import com.example.iot.util.SwitchUtil;
@SuppressLint(value={"DefaultLocale","SetTextI18n"})
public class LightActivity extends AppCompatActivity implements SensorEventListener {
    private TextView tv_light; // 声明一个文本视图对象
    private SensorManager mSensorMgr; // 声明一个传感管理器对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_light);
        CheckBox ck_bright = findViewById(R.id.ck_bright);
        // 检查屏幕亮度是否为自动调节
        if (SwitchUtil.getAutoBrightStatus(this)) {
            ck_bright.setChecked(true);
        }
        // Android8.0之后普通应用不允许修改系统设置
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            ck_bright.setOnCheckedChangeListener((buttonView, isChecked) -> {
                // 设置是否开启屏幕亮度的自动调节
                SwitchUtil.setAutoBrightStatus(this, isChecked);
            });
        } else {
            ck_bright.setEnabled(false);
        }
        tv_light = findViewById(R.id.tv_light);
        // 从系统服务中获取传感管理器对象
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }
    @Override
    protected void onPause() {
        super.onPause();
        mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器
    }
    @Override
    protected void onResume() {
        super.onResume();
        // 给光线传感器注册传感监听器
        mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(Sensor.TYPE_LIGHT),
                SensorManager.SENSOR_DELAY_NORMAL);
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_LIGHT) { // 光线强度变更事件
            float light_strength = event.values[0];
            tv_light.setText(DateUtil.getNowTime() + " 当前光线强度为" + light_strength);
        }
    }
    //当传感器精度改变时回调该方法,一般无需处理
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

四、陀螺仪

陀螺仪是测量平衡的仪器,它的测量结果为当前与上次位置之间的倾斜角度,这个角度描述的是三维空间上的夹角,因而其数值由x、y、z三个坐标轴上的角度偏移组成。 由于陀螺仪具备三维角度的测量功能,因此它又被称作角速度传感器。 加速度传感器只能检测线性距离的大小,而陀螺仪能够检测旋转角度的大小,所以利用陀螺仪可以还原三维物体的转动行为。

运行测试效果如下 随着手机的转动示数会跟着变化

代码如下

package com.example.iot;
import android.annotation.SuppressLint;
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.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.iot.util.DateUtil;
import java.util.List;
@SuppressLint("DefaultLocale")
public class GyroscopeActivity extends AppCompatActivity implements SensorEventListener {
    private static final float NS2S = 1.0f / 1000000000.0f; // 将纳秒转化为秒
    private TextView tv_gyroscope; // 声明一个文本视图对象
    private SensorManager mSensorMgr; // 声明一个传感管理器对象
    private float mTimestamp; // 记录上次的时间戳
    private float mAngle[] = new float[3]; // 记录xyz三个方向上的旋转角度
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gyroscope);
        tv_gyroscope = findViewById(R.id.tv_gyroscope);
        // 从系统服务中获取传感管理器对象
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }
    @Override
    protected void onPause() {
        super.onPause();
        mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器
    }
    @Override
    protected void onResume() {
        super.onResume();
        // 获取当前设备支持的传感器列表
        List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
        boolean isSuitable = false;
        for (Sensor sensor : sensorList) {
            if (sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 找到陀螺仪
                isSuitable = true;
                break;
            }
        }
        if (isSuitable) { // 找到了陀螺仪
            // 给陀螺仪传感器注册传感监听器
            mSensorMgr.registerListener(this,
                    mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
                    SensorManager.SENSOR_DELAY_FASTEST);
        } else { // 未找到陀螺仪
            tv_gyroscope.setText("当前设备不支持陀螺仪,请检查是否存在陀螺仪传感器");
        }
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 陀螺仪角度变更事件
            if (mTimestamp != 0) {
                final float dT = (event.timestamp - mTimestamp) * NS2S;
                mAngle[0] += event.values[0] * dT;
                mAngle[1] += event.values[1] * dT;
                mAngle[2] += event.values[2] * dT;
                // x轴的旋转角度,手机平放桌上,然后绕侧边转动
                float angleX = (float) Math.toDegrees(mAngle[0]);
                // y轴的旋转角度,手机平放桌上,然后绕底边转动
                float angleY = (float) Math.toDegrees(mAngle[1]);
                // z轴的旋转角度,手机平放桌上,然后水平旋转
                float angleZ = (float) Math.toDegrees(mAngle[2]);
                String desc = String.format("%s 陀螺仪检测到当前位置为:\n" +
                                "x轴方向的转动角度为%.6f,\n" +
                                "y轴方向的转动角度为%.6f,\n" +
                                "z轴方向的转动角度为%.6f。",
                        DateUtil.getNowTime(), angleX, angleY, angleZ);
                tv_gyroscope.setText(desc);
            }
            mTimestamp = event.timestamp;
        }
    }
    //当传感器精度改变时回调该方法,一般无需处理
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

创作不易 觉得有帮助请点赞关注收藏~~~

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
相关文章
|
3月前
|
JSON JavaScript 前端开发
harmony-chatroom 自研纯血鸿蒙OS Next 5.0聊天APP实战案例
HarmonyOS-Chat是一个基于纯血鸿蒙OS Next5.0 API12实战开发的聊天应用程序。这个项目使用了ArkUI和ArkTS技术栈,实现了类似微信的消息UI布局、输入框光标处插入文字、emoji表情图片/GIF动图、图片预览、红包、语音/位置UI、长按语音面板等功能。
284 2
|
4月前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
41 3
|
4月前
|
JavaScript 小程序 开发者
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
755 0
|
4月前
|
Android开发
Android实战之如何快速实现自动轮播图
本文介绍了在 Android 中使用 `ViewPager2` 和自定义适配器实现轮播图的方法,包括添加依赖、布局配置、创建适配器及实现自动轮播等步骤。
151 0
|
4月前
|
Android开发
Android开发显示头部Bar的需求解决方案--Android应用实战
Android开发显示头部Bar的需求解决方案--Android应用实战
48 0
|
5月前
|
开发工具 Android开发 git
Android实战之组件化中如何进行版本控制和依赖管理
本文介绍了 Git Submodules 的功能及其在组件化开发中的应用。Submodules 允许将一个 Git 仓库作为另一个仓库的子目录,有助于保持模块独立、代码重用和版本控制。虽然存在一些缺点,如增加复杂性和初始化时间,但通过最佳实践可以有效利用其优势。
68 3
|
5月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
422 9
|
5月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
211 1
|
5月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
180 5
|
5月前
|
编解码 前端开发 Android开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
411 12

热门文章

最新文章

  • 1
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    24
  • 2
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    33
  • 3
    Android历史版本与APK文件结构
    121
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    57
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    37
  • 8
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    73
  • 9
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    119
  • 10
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
    29